|
84417
|
2905
|
47
|
2026-05-28T11:41:25.801641+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968485801_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox•00DFileEdit→ViewHistoryBookmarksProfilesTo Firefox•00DFileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com100% C28 • Thu 28 May 14:41:25Lukas Kovalik2:41 PM | Lukas/Stefka 12111:11...
|
NULL
|
493524023284457889
|
NULL
|
click
|
ocr
|
NULL
|
Firefox•00DFileEdit→ViewHistoryBookmarksProfilesTo Firefox•00DFileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com100% C28 • Thu 28 May 14:41:25Lukas Kovalik2:41 PM | Lukas/Stefka 12111:11...
|
84414
|
NULL
|
NULL
|
NULL
|
|
84416
|
2906
|
46
|
2026-05-28T11:41:25.693187+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968485693_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calenosrViewWindow#github.comv Gooc e Gemin notion calenosrViewWindow#github.comv Gooc e GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• Codel17 Pull requests0. AgeMay 2026Sun 22Mon2;motine nintove poronter cooret fon ouysAndrea Zlatanova (Parental Leave - 189 days)Laura Zelinkova (PTO - 4 days)obonk ho cuy an25 26@ Scheduling8 Meet with.Stefka StoyanovaFamll• Work relatedlrolas• vybavovack• Holidays in Bulgaria•1 Sviatky y [EMAIL] kounlikaminnu com• lukas• My ca• Who's Ouwakownllkomaill.com• [EMAIL]+ Add calendar accountEB Add Notion databasev d0preparatioThu 28JO0% L7Thu 28 May 14:41:25Satslkrorcch taue Pro.(Adelina Gandzhurova (PT._PxS@ SyneTech Load ChuoteJiminny e Recall. ai: Deskes(Stefka Greg 11 4-15 PM...
|
NULL
|
-5157220647697938155
|
NULL
|
click
|
ocr
|
NULL
|
notion calenosrViewWindow#github.comv Gooc e Gemin notion calenosrViewWindow#github.comv Gooc e GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• Codel17 Pull requests0. AgeMay 2026Sun 22Mon2;motine nintove poronter cooret fon ouysAndrea Zlatanova (Parental Leave - 189 days)Laura Zelinkova (PTO - 4 days)obonk ho cuy an25 26@ Scheduling8 Meet with.Stefka StoyanovaFamll• Work relatedlrolas• vybavovack• Holidays in Bulgaria•1 Sviatky y [EMAIL] kounlikaminnu com• lukas• My ca• Who's Ouwakownllkomaill.com• [EMAIL]+ Add calendar accountEB Add Notion databasev d0preparatioThu 28JO0% L7Thu 28 May 14:41:25Satslkrorcch taue Pro.(Adelina Gandzhurova (PT._PxS@ SyneTech Load ChuoteJiminny e Recall. ai: Deskes(Stefka Greg 11 4-15 PM...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84415
|
2906
|
45
|
2026-05-28T11:41:06.620043+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968466620_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calenosrViewWindow#github.comv Gooc e Gemin notion calenosrViewWindow#github.comv Gooc e GeminiPipelines - jiminny/appGemini 3.1 Pro ~reauots now ownersroe toexUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: Xparent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiThu 28 May 14:41:06May 2026Thu?Fri 22• Codel17 Pull requests0. Agemans niihor tomieCoon "lou duyAndrea Zlatanova (Parental Leave - 189 days)Monya(Laura Zelinkova (PTO - 4 days)TueyWedkn@ Scheduling8 Meet withStefka StoyanovaSummarize page• Work relatedlrolas• vybavovack• Holidays in Bulgaria• Sviatky y [EMAIL]@jiminny.com• lukas• My cal• Who's Ouwakownllkomaill.com• [EMAIL]+ Add calendar accountEB Add Notion databasev d0...
|
NULL
|
8530441243552898177
|
NULL
|
idle
|
ocr
|
NULL
|
notion calenosrViewWindow#github.comv Gooc e Gemin notion calenosrViewWindow#github.comv Gooc e GeminiPipelines - jiminny/appGemini 3.1 Pro ~reauots now ownersroe toexUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: Xparent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiThu 28 May 14:41:06May 2026Thu?Fri 22• Codel17 Pull requests0. Agemans niihor tomieCoon "lou duyAndrea Zlatanova (Parental Leave - 189 days)Monya(Laura Zelinkova (PTO - 4 days)TueyWedkn@ Scheduling8 Meet withStefka StoyanovaSummarize page• Work relatedlrolas• vybavovack• Holidays in Bulgaria• Sviatky y [EMAIL]@jiminny.com• lukas• My cal• Who's Ouwakownllkomaill.com• [EMAIL]+ Add calendar accountEB Add Notion databasev d0...
|
84411
|
NULL
|
NULL
|
NULL
|
|
84414
|
2905
|
46
|
2026-05-28T11:41:05.200968+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968465200_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox•00DFileEdit→ViewHistoryBookmarksProfilesTo Firefox•00DFileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com100% C28 • Thu 28 May 14:41:04Lukas Kovalik2:41 PM | Lukas/Stefka 12110:50...
|
NULL
|
7832036538997513749
|
NULL
|
visual_change
|
ocr
|
NULL
|
Firefox•00DFileEdit→ViewHistoryBookmarksProfilesTo Firefox•00DFileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com100% C28 • Thu 28 May 14:41:04Lukas Kovalik2:41 PM | Lukas/Stefka 12110:50...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84413
|
2905
|
45
|
2026-05-28T11:41:02.048008+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968462048_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxFile•00.Edit→ViewHistoryBookmarksProfilesTo FirefoxFile•00.Edit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com100% C28 • Thu 28 May 14:41:01Lukas Kovalik2:41 PM | Lukas/Stefka 12110:47...
|
NULL
|
7134436703543992239
|
NULL
|
visual_change
|
ocr
|
NULL
|
FirefoxFile•00.Edit→ViewHistoryBookmarksProfilesTo FirefoxFile•00.Edit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com100% C28 • Thu 28 May 14:41:01Lukas Kovalik2:41 PM | Lukas/Stefka 12110:47...
|
84412
|
NULL
|
NULL
|
NULL
|
|
84412
|
2905
|
44
|
2026-05-28T11:40:40.387790+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968440387_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox•00DFileEdit→ViewHistoryBookmarksProfilesTo Firefox•00DFileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comlool100% C28 • Thu 28 May 14:40:39Lukas Kovalik2:40 PM | Lukas/Stefka 12110:25...
|
NULL
|
-4632894186372833616
|
NULL
|
click
|
ocr
|
NULL
|
Firefox•00DFileEdit→ViewHistoryBookmarksProfilesTo Firefox•00DFileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comlool100% C28 • Thu 28 May 14:40:39Lukas Kovalik2:40 PM | Lukas/Stefka 12110:25...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84411
|
2906
|
44
|
2026-05-28T11:40:36.084723+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968436084_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calenosrViewWindow#github.comv Gooc e Gemin notion calenosrViewWindow#github.comv Gooc e GeminiPipelines - jiminny/appreauots now ownersroe toexUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tt»en3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute mietionv dertltteThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• Codel17 Pull requests0. AgeMay 2026SunyhMony:weuns naistore parehter coovettowooreAndres Ziatanova (Parental Leave - 189 days)Laura Zelinkova (PTO - 4 days)ooonk nondsytenTreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:35Sat30@ Scheduling8 Meet with.Stefka StoyanovaFamll• Work relatedlrolasvybavovack• Holidays in Bulgaria• Sviatky y [EMAIL] koualikaminnu con6 tukas• My ca• Who's OuTTkowninkomaillcom• [EMAIL]+ Add calendar accountEB Add Notion databasev d0Tech Lead ChapterThank you's 5-30 PM...
|
NULL
|
-5669512397939114986
|
NULL
|
visual_change
|
ocr
|
NULL
|
notion calenosrViewWindow#github.comv Gooc e Gemin notion calenosrViewWindow#github.comv Gooc e GeminiPipelines - jiminny/appreauots now ownersroe toexUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tt»en3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute mietionv dertltteThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• Codel17 Pull requests0. AgeMay 2026SunyhMony:weuns naistore parehter coovettowooreAndres Ziatanova (Parental Leave - 189 days)Laura Zelinkova (PTO - 4 days)ooonk nondsytenTreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:35Sat30@ Scheduling8 Meet with.Stefka StoyanovaFamll• Work relatedlrolasvybavovack• Holidays in Bulgaria• Sviatky y [EMAIL] koualikaminnu con6 tukas• My ca• Who's OuTTkowninkomaillcom• [EMAIL]+ Add calendar accountEB Add Notion databasev d0Tech Lead ChapterThank you's 5-30 PM...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84410
|
2905
|
43
|
2026-05-28T11:40:32.900516+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968432900_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox•00DFileEdit→ViewHistoryBookmarksProfilesTo Firefox•00DFileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comlool100% C28 • Thu 28 May 14:40:32=Lukas Kovalik2:40 PM | Lukas/Stefka 12110:18...
|
NULL
|
-2682557249797950036
|
NULL
|
visual_change
|
ocr
|
NULL
|
Firefox•00DFileEdit→ViewHistoryBookmarksProfilesTo Firefox•00DFileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comlool100% C28 • Thu 28 May 14:40:32=Lukas Kovalik2:40 PM | Lukas/Stefka 12110:18...
|
84406
|
NULL
|
NULL
|
NULL
|
|
84409
|
2906
|
43
|
2026-05-28T11:40:31.570628+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968431570_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calenosrViewWindow#github.comv Gooc e Gemin notion calenosrViewWindow#github.comv Gooc e GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimiriwoonte Roso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Subramaaian at 27/05/202O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr orocaodesteo te ctioren ane draceuivexiesThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYour Jiminny chats aren't used to improve our modeis. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page• CodelPull requests0. Age© Schedulings,© kovaliklukas@gma... DefaultDomace prace•Familo• TravelWork related•relax• usualwbavova &k• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@[EMAIL]@jiminny.com5Mv cal• Holidays in Bulgari:Wha'e Ount@[EMAIL]+ Add calendar accouns82 Add Notion databaseNotion anosa NotinThu 28Thu 28 May 14:40:31Sat30May 2026SunyhMon7:weuns naistowe parchten coove chonooyAndres Ziatanova (Parental Leave - 189 days)Laura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Kebeces buder Phoenian undtnorord rmStelka StovanoyalStovan ihneySteliyan [EMAIL] Dasy:PM....
|
NULL
|
7795596141297049741
|
NULL
|
click
|
ocr
|
NULL
|
notion calenosrViewWindow#github.comv Gooc e Gemin notion calenosrViewWindow#github.comv Gooc e GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimiriwoonte Roso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Subramaaian at 27/05/202O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr orocaodesteo te ctioren ane draceuivexiesThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYour Jiminny chats aren't used to improve our modeis. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page• CodelPull requests0. Age© Schedulings,© kovaliklukas@gma... DefaultDomace prace•Familo• TravelWork related•relax• usualwbavova &k• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@[EMAIL]@jiminny.com5Mv cal• Holidays in Bulgari:Wha'e Ount@[EMAIL]+ Add calendar accouns82 Add Notion databaseNotion anosa NotinThu 28Thu 28 May 14:40:31Sat30May 2026SunyhMon7:weuns naistowe parchten coove chonooyAndres Ziatanova (Parental Leave - 189 days)Laura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Kebeces buder Phoenian undtnorord rmStelka StovanoyalStovan ihneySteliyan [EMAIL] Dasy:PM....
|
84408
|
NULL
|
NULL
|
NULL
|
|
84408
|
2906
|
42
|
2026-05-28T11:40:30.448322+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968430448_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calchostViewWindow#github.comv Gooc le Gemi notion calchostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavots now ownersroe tooAxUeoered tines on New codJY-20963 fix deleted object impsim cwdsycaotionslEmnlltcthttrM Inbox (1,733) - lukas.kovalik @jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system (supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr orocaodesteo te ctioren ane draceuivexiesThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiemeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYour Jiminny chats aren't used to improve our modeis. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page• CodelPull requests(. Age© Schedulings,© kovaliklukas@gma... DefaultDomace prace•Familo• TravelWork related•relax• usualwbavova &k• Sport• Stúdium5 Holidave in Bulaaris® Sviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@[EMAIL]@jiminny.com5Mv cal• Holidays in Bulgari6 Whare Out@[EMAIL]+ Add calendar account82 Add Notion databaseNotion anosa Notinv c0Thu 28Thu 28 May 14:40:30Sat30May 2026SunyMon?:weuns niaistove parchten coove chonooyAndre/htanoua(Parantalllonw. 189 dhvsLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Kebeces buder Phoenoian undtnorord rStelka StovanoyalStovan ihneySteliyan [EMAIL] Das-PMl...
|
NULL
|
-8898058653531089619
|
NULL
|
typing_pause
|
ocr
|
NULL
|
notion calchostViewWindow#github.comv Gooc le Gemi notion calchostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavots now ownersroe tooAxUeoered tines on New codJY-20963 fix deleted object impsim cwdsycaotionslEmnlltcthttrM Inbox (1,733) - lukas.kovalik @jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system (supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr orocaodesteo te ctioren ane draceuivexiesThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiemeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYour Jiminny chats aren't used to improve our modeis. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminiSummarize page• CodelPull requests(. Age© Schedulings,© kovaliklukas@gma... DefaultDomace prace•Familo• TravelWork related•relax• usualwbavova &k• Sport• Stúdium5 Holidave in Bulaaris® Sviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@[EMAIL]@jiminny.com5Mv cal• Holidays in Bulgari6 Whare Out@[EMAIL]+ Add calendar account82 Add Notion databaseNotion anosa Notinv c0Thu 28Thu 28 May 14:40:30Sat30May 2026SunyMon?:weuns niaistove parchten coove chonooyAndre/htanoua(Parantalllonw. 189 dhvsLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Kebeces buder Phoenoian undtnorord rStelka StovanoyalStovan ihneySteliyan [EMAIL] Das-PMl...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84407
|
2906
|
41
|
2026-05-28T11:40:28.585453+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968428585_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appGemini 3.1 Pro ~reavors now ownerstoe tooAxUemered tines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: Xparent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & Camini• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:28Sat30Kebeces buder Phoenian undtnorord rm© Scheduling) kovaliklukas@gma... DefaultDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BuloarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in BulgarioWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Das-PMlSummarize page...
|
NULL
|
-1127969549900429045
|
NULL
|
click
|
ocr
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appGemini 3.1 Pro ~reavors now ownerstoe tooAxUemered tines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: Xparent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & Camini• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:28Sat30Kebeces buder Phoenian undtnorord rm© Scheduling) kovaliklukas@gma... DefaultDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BuloarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in BulgarioWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Das-PMlSummarize page...
|
84405
|
NULL
|
NULL
|
NULL
|
|
84406
|
2905
|
42
|
2026-05-28T11:40:27.681981+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968427681_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox•00 .FileEdit→ViewHistoryBookmarksProfilesT Firefox•00 .FileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comldol100% C28 • Thu 28 May 14:40:27=Lukas Kovalik2:40 PM | Lukas/Stefka 12110:13...
|
NULL
|
-5782076089631434693
|
NULL
|
visual_change
|
ocr
|
NULL
|
Firefox•00 .FileEdit→ViewHistoryBookmarksProfilesT Firefox•00 .FileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comldol100% C28 • Thu 28 May 14:40:27=Lukas Kovalik2:40 PM | Lukas/Stefka 12110:13...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84405
|
2906
|
40
|
2026-05-28T11:40:27.096124+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968427096_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:26Sat30Kebeces buder Phoenian undtnorord rm25© Scheduling8 Meet withKovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
4302707255365077061
|
NULL
|
click
|
ocr
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:26Sat30Kebeces buder Phoenian undtnorord rm25© Scheduling8 Meet withKovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84404
|
2906
|
39
|
2026-05-28T11:40:25.572107+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968425572_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:25Sat30Kebeces buder Phoenian undtnorord rm25© Scheduling8 Meet with.Kovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
5162017231465672185
|
NULL
|
typing_pause
|
ocr
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:25Sat30Kebeces buder Phoenian undtnorord rm25© Scheduling8 Meet with.Kovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
84403
|
NULL
|
NULL
|
NULL
|
|
84403
|
2906
|
38
|
2026-05-28T11:40:24.468127+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968424468_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:24Sat3028Kebeces buder Phoenian undtnorord rm© SchedulingKovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
-4187686335687323256
|
NULL
|
click
|
ocr
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:24Sat3028Kebeces buder Phoenian undtnorord rm© SchedulingKovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84402
|
2905
|
41
|
2026-05-28T11:40:22.506360+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968422506_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox•00DFileEdit→ViewHistoryBookmarksProfilesTo Firefox•00DFileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comlool100% C28 • Thu 28 May 14:40:22Lukas Kovalik2:40 PM | Lukas/Stefka 12110:08...
|
NULL
|
3841589094381602130
|
NULL
|
visual_change
|
ocr
|
NULL
|
Firefox•00DFileEdit→ViewHistoryBookmarksProfilesTo Firefox•00DFileEdit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comlool100% C28 • Thu 28 May 14:40:22Lukas Kovalik2:40 PM | Lukas/Stefka 12110:08...
|
84398
|
NULL
|
NULL
|
NULL
|
|
84401
|
2906
|
37
|
2026-05-28T11:40:20.743169+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968420743_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:20Sat3028Kebeces buder Phoenian undtnorord rm© SchedulingKovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
-5559194789185332128
|
NULL
|
click
|
ocr
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:20Sat3028Kebeces buder Phoenian undtnorord rm© SchedulingKovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
84400
|
NULL
|
NULL
|
NULL
|
|
84400
|
2906
|
36
|
2026-05-28T11:40:19.679329+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968419679_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:19Sat30Kebeces buder Phoenian undtnorord rm25© Scheduling8 Meet with.Kovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
3214189928495303095
|
NULL
|
typing_pause
|
ocr
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:19Sat30Kebeces buder Phoenian undtnorord rm25© Scheduling8 Meet with.Kovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84399
|
2906
|
35
|
2026-05-28T11:40:18.644836+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968418644_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:18Sat3028Kebeces buder Phoenian undtnorord rm© SchedulingKovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
-8241048339455273342
|
NULL
|
click
|
ocr
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:18Sat3028Kebeces buder Phoenian undtnorord rm© SchedulingKovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
84397
|
NULL
|
NULL
|
NULL
|
|
84398
|
2905
|
40
|
2026-05-28T11:40:17.469009+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968417469_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxFile•00.Edit→ViewHistoryBookmarksProfilesTo FirefoxFile•00.Edit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comlool100% C28 • Thu 28 May 14:40:17Lukas Kovalik2:40 PM | Lukas/Stefka 12110:03...
|
NULL
|
2533917254270978083
|
NULL
|
visual_change
|
ocr
|
NULL
|
FirefoxFile•00.Edit→ViewHistoryBookmarksProfilesTo FirefoxFile•00.Edit→ViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comlool100% C28 • Thu 28 May 14:40:17Lukas Kovalik2:40 PM | Lukas/Stefka 12110:03...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84397
|
2906
|
34
|
2026-05-28T11:40:17.357610+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968417357_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:17Sat3028Kebeces buder Phoenian undtnorord rm© SchedulingKovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
-5220161743146114286
|
NULL
|
visual_change
|
ocr
|
NULL
|
notion calehostViewWindow#github.comv Gooc le Gemi notion calehostViewWindow#github.comv Gooc le GeminiPipelines - jiminny/appreavors now ownerstoe tooxUewredtines on New codJY-20963 fix deleted object impslm cwdsycaotionslEmnlltcthtteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork). you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr oropdodesteo te ctioren ane draceuivexisThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmeasute me tierv dertteeThe Reality Check: The lock logic (if (! is null(Redis::get(SlockKey))) ) is not atomicThe Result: Because these are now truly parallel processes, both workers could evaluate thatrlemennne pyaer shme nierosoeond. doin sop nuline toln diitnetmlereesimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYoe lim nou Chate teho' uend to imnrmy our moddle Camioiie Allt cao make mtakhe to donbls chch+ Yoir oiacy & CaminiSummarize page• CodelPull requests0. AgeMay 2026SunyhMony:weuns naistowe parchten coove chonooyAndre/htanoua(Parantall lonw. 189 dhysLaura Zelinkova (PTO - 4 days)TreydWedklodotamalor PTO-0Kara Jones (Unpaid Leave of Absence - 9 days)Thu 28Thu 28 May 14:40:17Sat3028Kebeces buder Phoenian undtnorord rm© SchedulingKovalkiurosymkn OcroukDomace prace•Familo• TravelWork related•relax• usualfwbavova &ks• Sport• Stúdium5 Holidave in BulaarisSviatky na SlovenskuSviatky v Bulharsku# [EMAIL]@lukas.kovalik@jiminny.com5Mv cal• Holidays in Bulgari:oWha'eOit@[EMAIL]+ Add calendar account82 Add Notion databaseNotion hoosa NotinSucoort Dawy:PMl...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84396
|
2906
|
33
|
2026-05-28T11:40:15.633097+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968415633_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
reauots now ownersroe toexUewredtines on New codJY reauots now ownersroe toexUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Subramaaian at 27/05/202O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: X=github.comv Gooc e GeminiGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork(), you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr orocaodesteo te ctioren ane draceuivexiesThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmesut me tior dertlorThe Reality Check: The lock logic (if (! is_null(Redis::get (SlockKey))) ) is not atomic.The Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYour Jiminny chats aren't used to improve our modeis. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminSummarize pageCYMON100% K5X- • Thu 28 May 14:40:16Q Type [ to search8 -1eodePull requests34Agents + ActionsUWiknlSecurity and qualty12lwInsights g Settings• Vasil-Jiminny requested your review on this pull request.Jy 20910 schedule parallel update target processing #12130 •11 OpenVasil-Jiminny wants to merge 65 commits into naster from JY-28910-schedule-parallel-update-target-processingQ) Conversation 17a Commits 65E Checks 3 B Files changed 15Vasil-Jiminny commented 2 days ago • editedJIRA: JY-20910Changes:• Introduced a new class AsyncUpdateSupervisor under the same Artisan aliases:update-entities. The command works as parent / supervisor process and spawns a child process for eachallaued taradt tund e Mitroatly aetiuity hodl onnartunityif a child process exits, the supervisor will restart it within 5 seconds.Ia SIGTERM is recerved. "will oronsoate it to child processes.This allows each indexing operation to run with its own memory signature.• Cleanup old one-time commands that we do not need anymore.• Drop total memory usage, as it makes no sense when two separate processes are spawn for indexing activities andopportunities.• Improved GracefullyStoppable trait to correctly print exit message after 10 seconds.• Reporting Datadog metrics is moved to a separate class to keep concerns of UpdateProcessManager more strict.• Tests are uodated accoro-nolv• Added startup and exit logs.Siartuo LoosSIGTERM logs:• Awaiting approvaleode-4764 -440 88801....@kovicwere vkulov@ LakyLak® TodorStamatovJiminnyilian-jiminnyyalokin-jiminnyAt least 1 approving review is required to merge this pullStill in progress? Convert to draftAssigneesNo ond=assion vourselLaoelsNone yetProjectsNone yetMiles omNo milestoneDevelopmentSuccesstully merging this pull request may close theseIssue?None wetNotifications2 UnsubscribeHighight All Match Case Match Diacriies Whoie Words1of 1 matchReached top of page, continued from bottom...
|
NULL
|
4284326810012478418
|
NULL
|
click
|
ocr
|
NULL
|
reauots now ownersroe toexUewredtines on New codJY reauots now ownersroe toexUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Subramaaian at 27/05/202O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: X=github.comv Gooc e GeminiGemini 3.1 Pro ~parent's memory space and open file descriptors. While you correctly purged MySQL andKedis connectionsin resecArterrork(), you missed the clasticsearch clent.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system ( supervisorctl ) sends a SIGTERM, the customAsuncuodaresuoervisor cachestr orocaodesteo te ctioren ane draceuivexiesThe Reality Check: In your (reapChildren() method, pcntl_waitpid(Spid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second araceful exit logic in GracefullyStoopable will be comoletely ianored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking data-tteelnl3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeeltiewmesut me tior dertlorThe Reality Check: The lock logic (if (! is_null(Redis::get (SlockKey))) ) is not atomic.The Result: Because these are now truly parallel processes, both workers could evaluate thatif statement at the eyact same microsecond. hath see nulll, and hoth nuch their metricosimultaneously. This defeats the lock and can lead to skewed Datadog graphs.The strategy you've chosen is definitely the right path, it just needs a few strict guardrails aroundhow PHP handles forking and locking to make it bulletproof.Would you like me to write out the exact code snippets to safely reset the Elasticsearch client and fixthe shutdown deadlock so you can drop them straight into your PR?Ask GeminilYour Jiminny chats aren't used to improve our modeis. Gemini is Al. It can make mistakes, so double check it. Your privacy & GeminSummarize pageCYMON100% K5X- • Thu 28 May 14:40:16Q Type [ to search8 -1eodePull requests34Agents + ActionsUWiknlSecurity and qualty12lwInsights g Settings• Vasil-Jiminny requested your review on this pull request.Jy 20910 schedule parallel update target processing #12130 •11 OpenVasil-Jiminny wants to merge 65 commits into naster from JY-28910-schedule-parallel-update-target-processingQ) Conversation 17a Commits 65E Checks 3 B Files changed 15Vasil-Jiminny commented 2 days ago • editedJIRA: JY-20910Changes:• Introduced a new class AsyncUpdateSupervisor under the same Artisan aliases:update-entities. The command works as parent / supervisor process and spawns a child process for eachallaued taradt tund e Mitroatly aetiuity hodl onnartunityif a child process exits, the supervisor will restart it within 5 seconds.Ia SIGTERM is recerved. "will oronsoate it to child processes.This allows each indexing operation to run with its own memory signature.• Cleanup old one-time commands that we do not need anymore.• Drop total memory usage, as it makes no sense when two separate processes are spawn for indexing activities andopportunities.• Improved GracefullyStoppable trait to correctly print exit message after 10 seconds.• Reporting Datadog metrics is moved to a separate class to keep concerns of UpdateProcessManager more strict.• Tests are uodated accoro-nolv• Added startup and exit logs.Siartuo LoosSIGTERM logs:• Awaiting approvaleode-4764 -440 88801....@kovicwere vkulov@ LakyLak® TodorStamatovJiminnyilian-jiminnyyalokin-jiminnyAt least 1 approving review is required to merge this pullStill in progress? Convert to draftAssigneesNo ond=assion vourselLaoelsNone yetProjectsNone yetMiles omNo milestoneDevelopmentSuccesstully merging this pull request may close theseIssue?None wetNotifications2 UnsubscribeHighight All Match Case Match Diacriies Whoie Words1of 1 matchReached top of page, continued from bottom...
|
84394
|
NULL
|
NULL
|
NULL
|
|
84395
|
2905
|
39
|
2026-05-28T11:40:07.980960+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968407980_m1.jpg...
|
Firefox
|
Meet - Lukas/Stefka 121 — Work
|
1
|
meet.google.com/axk-zwsm-vok?authuser=lukas.kovali meet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Meet - Lukas/Stefka 121
Close tab
New Tab
Open Goo Meet - Lukas/Stefka 121
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
People
1
Take notes with Gemini
Take notes with Gemini
Gemini
Gemini
Lukas Kovalik
2:40
PM
Lukas/Stefka 121
Lukas/Stefka 121
Audio settings
Turn on microphone
Video settings
Turn on camera
Share screen
Send a reaction
Turn on captions
Raise hand (ctrl + ⌘ + h)
More options
Leave call
Meeting details
Chat with everyone
Meeting tools...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Meet - Lukas/Stefka 121","depth":4,"bounds":{"left":0.0,"top":0.072222225,"width":0.033680554,"height":0.045555554},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0013888889,"top":0.072222225,"width":0.010416667,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.005902778,"top":0.12,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.7977778,"width":0.033680554,"height":0.043333333},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.0,"top":0.8411111,"width":0.033680554,"height":0.038333334},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.0,"top":0.8794444,"width":0.033680554,"height":0.03888889},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.0,"top":0.91833335,"width":0.033680554,"height":0.038333334},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.95666665,"width":0.033680554,"height":0.043333333},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"People","depth":8,"bounds":{"left":0.88784724,"top":0.08722222,"width":0.039930556,"height":0.04},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.915625,"top":0.09888889,"width":0.0038194444,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Take notes with Gemini","depth":8,"bounds":{"left":0.93333334,"top":0.08722222,"width":0.025,"height":0.04},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Take notes with Gemini","depth":11,"bounds":{"left":0.9361111,"top":0.09888889,"width":0.06388891,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Gemini","depth":8,"bounds":{"left":0.9638889,"top":0.08722222,"width":0.025,"height":0.04},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Gemini","depth":11,"bounds":{"left":0.96666664,"top":0.09888889,"width":0.028125,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":11,"bounds":{"left":0.05590278,"top":0.87166667,"width":0.06875,"height":0.022777777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2:40","depth":6,"bounds":{"left":0.050347224,"top":0.9444444,"width":0.023263888,"height":0.022777777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PM","depth":6,"bounds":{"left":0.077083334,"top":0.9444444,"width":0.016319444,"height":0.022777777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Lukas/Stefka 121","depth":6,"bounds":{"left":0.11076389,"top":0.9111111,"width":0.08506945,"height":0.08888888},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lukas/Stefka 121","depth":9,"bounds":{"left":0.11076389,"top":0.9444444,"width":0.08506945,"height":0.022777777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Audio settings","depth":8,"bounds":{"left":0.32118055,"top":0.9288889,"width":0.06111111,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on microphone","depth":8,"bounds":{"left":0.34895834,"top":0.9288889,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXButton","text":"Video settings","depth":7,"bounds":{"left":0.38784721,"top":0.9288889,"width":0.06111111,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on camera","depth":7,"bounds":{"left":0.415625,"top":0.9288889,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share screen","depth":6,"bounds":{"left":0.45451388,"top":0.9288889,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Send a reaction","depth":6,"bounds":{"left":0.49895832,"top":0.9288889,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on captions","depth":7,"bounds":{"left":0.5434028,"top":0.9288889,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Raise hand (ctrl + ⌘ + h)","depth":6,"bounds":{"left":0.58784723,"top":0.9288889,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options","depth":6,"bounds":{"left":0.6322917,"top":0.9288889,"width":0.025,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Leave call","depth":6,"bounds":{"left":0.6628472,"top":0.9288889,"width":0.05,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Meeting details","depth":6,"bounds":{"left":0.89166665,"top":0.9288889,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat with everyone","depth":6,"bounds":{"left":0.925,"top":0.9288889,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Meeting tools","depth":6,"bounds":{"left":0.9583333,"top":0.9288889,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3310113497437857030
|
5674709751569638176
|
visual_change
|
hybrid
|
NULL
|
Meet - Lukas/Stefka 121
Close tab
New Tab
Open Goo Meet - Lukas/Stefka 121
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
People
1
Take notes with Gemini
Take notes with Gemini
Gemini
Gemini
Lukas Kovalik
2:40
PM
Lukas/Stefka 121
Lukas/Stefka 121
Audio settings
Turn on microphone
Video settings
Turn on camera
Share screen
Send a reaction
Turn on captions
Raise hand (ctrl + ⌘ + h)
More options
Leave call
Meeting details
Chat with everyone
Meeting tools
FirefoxFileEditViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comloolLA100% CThu 28 May 14:40:07=Lukas Kovalik2:40 PM | Lukas/Stefka 121• 9:53...
|
84393
|
NULL
|
NULL
|
NULL
|
|
84394
|
2906
|
32
|
2026-05-28T11:40:05.700690+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968405700_m2.jpg...
|
Firefox
|
Meet - Lukas/Stefka 121 — Work
|
1
|
meet.google.com/axk-zwsm-vok?authuser=lukas.kovali meet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Meet - Lukas/Stefka 121
Close tab
New Tab
Open Goo Meet - Lukas/Stefka 121
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
People
1
Take notes with Gemini
Take notes with Gemini
Gemini
Gemini
Lukas Kovalik
2:40
PM
Lukas/Stefka 121
Lukas/Stefka 121
Audio settings
Turn on microphone
Video settings
Turn on camera
Share screen
Send a reaction
Turn on captions
Raise hand (ctrl + ⌘ + h)
More options
Leave call
Meeting details
Chat with everyone
Meeting tools...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Meet - Lukas/Stefka 121","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.016123671,"height":-0.051875472},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.27094415,"top":1.0,"width":0.004986702,"height":-0.051875472},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.27310506,"top":1.0,"width":0.010638298,"height":-0.086193085},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"People","depth":8,"bounds":{"left":0.6953125,"top":1.0,"width":0.019115692,"height":-0.06264961},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.70861036,"top":1.0,"width":0.0018284575,"height":-0.071029544},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Take notes with Gemini","depth":8,"bounds":{"left":0.71708775,"top":1.0,"width":0.011968086,"height":-0.06264961},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Take notes with Gemini","depth":11,"bounds":{"left":0.7184175,"top":1.0,"width":0.043550532,"height":-0.071029544},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Gemini","depth":8,"bounds":{"left":0.73171544,"top":1.0,"width":0.011968086,"height":-0.06264961},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Gemini","depth":11,"bounds":{"left":0.7330452,"top":1.0,"width":0.013464096,"height":-0.071029544},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2:40","depth":6,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PM","depth":6,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Lukas/Stefka 121","depth":6,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lukas/Stefka 121","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Audio settings","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on microphone","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXButton","text":"Video settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on camera","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share screen","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Send a reaction","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on captions","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Raise hand (ctrl + ⌘ + h)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Leave call","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Meeting details","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat with everyone","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Meeting tools","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3310113497437857030
|
5674709751569638176
|
visual_change
|
hybrid
|
NULL
|
Meet - Lukas/Stefka 121
Close tab
New Tab
Open Goo Meet - Lukas/Stefka 121
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
People
1
Take notes with Gemini
Take notes with Gemini
Gemini
Gemini
Lukas Kovalik
2:40
PM
Lukas/Stefka 121
Lukas/Stefka 121
Audio settings
Turn on microphone
Video settings
Turn on camera
Share screen
Send a reaction
Turn on captions
Raise hand (ctrl + ⌘ + h)
More options
Leave call
Meeting details
Chat with everyone
Meeting tools
FircroxPipelines - jiminny/appreauots now ownersroe toexUewredtines on New codJY-20963 fix deleted object impsM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Subramanian at 27/05/202O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel upc• =github.com~ Google GeminiGemini 3.1 Pro ~Notme creweed ewwortrostmulti-processing edge cases in PHP ( pcntl)) are going to actively sabotage your intentions.Here is how the issues we found directly impact the goals of your PR:1. Goal: Complete Process Isolation ("да не си пречат")• The Intent: Forking two separate processes so Activities and Opportunities index in parallelwithout blocking each other.The Reality Check: Because you are using pentl_fork(), the child processes inherit theparent's memory space and open file descriptors. While you correctly purged MySQL andRedis connections in resetAfterFork() . you missed the Elasticsearch client.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notIntertenna, tnev willliteralliv collide at the nerwork laver. causina corruoted nawloads. cuRyexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system (supervisorctl ) sends a SIGTERM, the customAsyncUpdateSupervisor catches it, propagates it to the children, and gracefully exits.The Reality Check: In your reapChildren() method, pcntl_waitpid($pid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second graceful exit logic in GracefullyStoppable will be completely ignored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking datauo.ion3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeetrlewmeastte metery derttedAsk GeminiYour lim nou chate trhn" uend to imnroy our moddle Camioiie 4l1t cao mata mtake co donbls chack " Yoir oracy & CaminSummarize pageCYMON100% KSX- • Thu 28 May 14:40:05Q Type ( to search8 -Pull requests34Agents + Actions08 WikiSecurity and quality 12wInsights g SettingsA Vasil-Jiminny requested your review on this pull request.Jy 20910 schedule parallel update target processing #12130 •11 OpenVasil-Jiminny wants to merge 65 commits into naster from JY-28910-schedule-parallel-update-target-processingQ) Conversation 17a Commits 65E Checks 3 B Files changed 15Vasil-Jiminny commented 2 days ago • editedJIRA: JY-20910Changes:• Introduced a new class AsyncUpdateSupervisor under the same Artisan aliases:update-entities. The command works as parent / supervisor process and spawns a child process for eachallaued taradt tund o Mitrootly aetuity hodl onnnetunttvif a child process exits, the supervisor will restart it within 5 seconds.Ia SIGTERM is recerved, "willl oronsoste it to child orocesses.This allows each indexing operation to run with its own memory signature.• Cleanup old one-time commands that we do not need anymore.• Drop total memory usage, as it makes no sense when two separate processes are spawn for indexing activities andopportunities.• Improved GracefullyStoppable trait to correctly print exit message after 10 seconds.• Reporting Datadog metrics is moved to a separate class to keep concerns of UpdateProcessManager more strict.• Tests are uodated accoro-nolv• Added startup and exit logs.Startup Logs:SIGTERM logs:• Awaiting approvaleode4764 -440 88801....@kovicwere vkulov@ LakyLak® TodorStamatovJiminnyilian-jiminnyyalokin-jiminnyAt least 1 approving review is required to merge this pullStill in progress? Convert to draftAssigneesNo ond-assian vourselLaoelsNone yetProjectsNone yetMiles omNo milestoneDevelopmentSuccesstully merging this pull request may close theseIssue?None wetNotifications2 UnsubscribeHighight All Match Case Match Diacriies Whole Words 1 of 1 matchReached top of page, continued from bottom...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84393
|
2905
|
38
|
2026-05-28T11:40:03.963341+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968403963_m1.jpg...
|
Firefox
|
Meet - Lukas/Stefka 121 — Work
|
1
|
meet.google.com/axk-zwsm-vok?authuser=lukas.kovali meet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Meet - Lukas/Stefka 121
Close tab
New Tab
Open Goo Meet - Lukas/Stefka 121
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
People
1
Take notes with Gemini
Take notes with Gemini
Gemini
Gemini
You’re continuously framed
Backgrounds and effects
More options for Lukas Kovalik
Lukas Kovalik
2:40
PM
Lukas/Stefka 121
Lukas/Stefka 121
Audio settings
Turn on microphone
Video settings
Turn on camera
Share screen
Send a reaction
Turn on captions
Raise hand (ctrl + ⌘ + h)
More options
Leave call
Meeting details
Chat with everyone
Meeting tools...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Meet - Lukas/Stefka 121","depth":4,"bounds":{"left":0.0,"top":0.072222225,"width":0.033680554,"height":0.045555554},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.0013888889,"top":0.072222225,"width":0.010416667,"height":0.016666668},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.005902778,"top":0.12,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.7977778,"width":0.033680554,"height":0.043333333},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.0,"top":0.8411111,"width":0.033680554,"height":0.038333334},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.0,"top":0.8794444,"width":0.033680554,"height":0.03888889},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.0,"top":0.91833335,"width":0.033680554,"height":0.038333334},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.95666665,"width":0.033680554,"height":0.043333333},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"People","depth":8,"bounds":{"left":0.88784724,"top":0.08722222,"width":0.039930556,"height":0.04},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":10,"bounds":{"left":0.915625,"top":0.09888889,"width":0.0038194444,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Take notes with Gemini","depth":8,"bounds":{"left":0.93333334,"top":0.08722222,"width":0.025,"height":0.04},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Take notes with Gemini","depth":11,"bounds":{"left":0.9361111,"top":0.09888889,"width":0.06388891,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Gemini","depth":8,"bounds":{"left":0.9638889,"top":0.08722222,"width":0.025,"height":0.04},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Gemini","depth":11,"bounds":{"left":0.96666664,"top":0.09888889,"width":0.028125,"height":0.017222222},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"You’re continuously framed","depth":7,"bounds":{"left":0.47256944,"top":0.5038889,"width":0.030555556,"height":0.04888889},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Backgrounds and effects","depth":7,"bounds":{"left":0.503125,"top":0.5038889,"width":0.030555556,"height":0.04888889},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options for Lukas Kovalik","depth":7,"bounds":{"left":0.53368056,"top":0.5061111,"width":0.027777778,"height":0.044444446},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Lukas Kovalik","depth":11,"bounds":{"left":0.05590278,"top":0.87166667,"width":0.06875,"height":0.022777777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2:40","depth":6,"bounds":{"left":0.050347224,"top":0.9444444,"width":0.023263888,"height":0.022777777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PM","depth":6,"bounds":{"left":0.077083334,"top":0.9444444,"width":0.016319444,"height":0.022777777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Lukas/Stefka 121","depth":6,"bounds":{"left":0.11076389,"top":0.9111111,"width":0.08506945,"height":0.08888888},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lukas/Stefka 121","depth":9,"bounds":{"left":0.11076389,"top":0.9444444,"width":0.08506945,"height":0.022777777},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Audio settings","depth":8,"bounds":{"left":0.32118055,"top":0.9288889,"width":0.06111111,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on microphone","depth":8,"bounds":{"left":0.34895834,"top":0.9288889,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXButton","text":"Video settings","depth":7,"bounds":{"left":0.38784721,"top":0.9288889,"width":0.06111111,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on camera","depth":7,"bounds":{"left":0.415625,"top":0.9288889,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share screen","depth":6,"bounds":{"left":0.45451388,"top":0.9288889,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Send a reaction","depth":6,"bounds":{"left":0.49895832,"top":0.9288889,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on captions","depth":7,"bounds":{"left":0.5434028,"top":0.9288889,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Raise hand (ctrl + ⌘ + h)","depth":6,"bounds":{"left":0.58784723,"top":0.9288889,"width":0.03888889,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options","depth":6,"bounds":{"left":0.6322917,"top":0.9288889,"width":0.025,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Leave call","depth":6,"bounds":{"left":0.6628472,"top":0.9288889,"width":0.05,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Meeting details","depth":6,"bounds":{"left":0.89166665,"top":0.9288889,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat with everyone","depth":6,"bounds":{"left":0.925,"top":0.9288889,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Meeting tools","depth":6,"bounds":{"left":0.9583333,"top":0.9288889,"width":0.033333335,"height":0.053333335},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
6468226353175045366
|
7692318023095997224
|
click
|
hybrid
|
NULL
|
Meet - Lukas/Stefka 121
Close tab
New Tab
Open Goo Meet - Lukas/Stefka 121
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
People
1
Take notes with Gemini
Take notes with Gemini
Gemini
Gemini
You’re continuously framed
Backgrounds and effects
More options for Lukas Kovalik
Lukas Kovalik
2:40
PM
Lukas/Stefka 121
Lukas/Stefka 121
Audio settings
Turn on microphone
Video settings
Turn on camera
Share screen
Send a reaction
Turn on captions
Raise hand (ctrl + ⌘ + h)
More options
Leave call
Meeting details
Chat with everyone
Meeting tools
FirefoxFileEditViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comloolLA100% CThu 28 May 14:40:03=Lukas Kovalik2:40 PM | Lukas/Stefka 121• 9:49...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84392
|
2906
|
31
|
2026-05-28T11:40:02.862189+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968402862_m2.jpg...
|
Firefox
|
Meet - Lukas/Stefka 121 — Work
|
1
|
meet.google.com/axk-zwsm-vok?authuser=lukas.kovali meet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
rircroxViewhsttonooountrnPotLe.WVindowHelp• =githu rircroxViewhsttonooountrnPotLe.WVindowHelp• =github.com/Mydoo oULLIou~ Google GeminiPipelines - jiminny/appGemini 3.1 Pro ~reauots now ownersroe toexUewredtines on New codJY-20963 fix deleted object impsM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Subramanian at 27/05/202O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XNonme creweedewwortrostmulti-processing edge cases in PHP ( pcntl)) are going to actively sabotage your intentions.Here is how the issues we found directly impact the goals of your PR:1. Goal: Complete Process Isolation ("да не си пречат")• The Intent: Forking two separate processes so Activities and Opportunities index in parallelwithout blocking each other.The Reality Check: Because you are using pentl_fork(), the child processes inherit theparent's memory space and open file descriptors. While you correctly purged MySQL andRedis connections in resetAfterFork() . you missed the Elasticsearch client.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system (supervisorctl ) sends a SIGTERM, the customAsyncUpdateSupervisor catches it, propagates it to the children, and gracefully exits.The Reality Check: In your reapChildren() method, pcntl_waitpid($pid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second graceful exit logic in GracefullyStoppable will be completely ignored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking datauo.ion3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeerlewmescute metery dertruedAsk GeminiYour lim nou chate trhn" uend to imnroy our moddle Camioiie 4l1t cao mata mtake co donbls chack " Yoir oracy & CaminSummarize pagePull requests34Agents + Actions0 WikiSecurity and quality 12wInsights g SettingsA Vasil-Jiminny requested your review on this pull request.Jy 20910 schedule parallel update target processing #12130 •11 OpenVasil-Jiminny wants to merge 65 commits into naster from JY-28910-schedule-parallel-update-target-processingQ) Conversation 17a Commits 65E Checks 3 B Files changed 15Vasil-Jiminny commented 2 days ago • editedJIRA: JY-20910Changes:• Introduced a new class AsyncUpdateSupervisor under the same Artisan aliases:update-entities. The command works as parent / supervisor process and spawns a child process for eachallaued taradt tund o Mitrootly aetuity hodl onnnetunttvif a child process exits, the supervisor will restart it within 5 seconds.Ia SIGTERM is recerved, "willl oronsoste it to child orocesses.This allows each indexing operation to run with its own memory signature.• Cleanup old one-time commands that we do not need anymore.• Drop total memory usage, as it makes no sense when two separate processes are spawn for indexing activities andopportunities.• Improved GracefullyStoppable trait to correctly print exit message after 10 seconds.• Reporting Datadog metrics is moved to a separate class to keep concerns of UpdateProcessManager more strict.• Tests are uodated accoro-nolv• Added startup and exit logs.Startup Logs:SIGTERM logs:Highight All Match Case Match Diacriies Whoie Words1of 1 matchReached top of page, continued from bottomOESOMОД100% KSa- • Thu 28 May 14:40:02Q Type ( to search8 -• Awaiting approvaleode+764 -440 8887KOVICWUTIe vkulov@ LakyLak® TodorStamatovJiminnyilian-jiminnyyalokin-jiminnyAt least 1 approving review is required to merge this pullStill in progress? Convert to draftAssigneesNo ond=assion vourselLaoelsNone yetProjectsNonc wetMiles omNo milestoneDevelopmentSuccesstully merging this pull request may close theseIssue?None wetNotifications2 Unsubscribe...
|
NULL
|
3285075741644521277
|
NULL
|
click
|
ocr
|
NULL
|
rircroxViewhsttonooountrnPotLe.WVindowHelp• =githu rircroxViewhsttonooountrnPotLe.WVindowHelp• =github.com/Mydoo oULLIou~ Google GeminiPipelines - jiminny/appGemini 3.1 Pro ~reauots now ownersroe toexUewredtines on New codJY-20963 fix deleted object impsM Inbox (1,733) - lukas.kovalik@jimirioonre Reso ve php 81.15 dedPlatform Sorint 5.02 - Platform TelimiomSona Subramanian at 27/05/202O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XNonme creweedewwortrostmulti-processing edge cases in PHP ( pcntl)) are going to actively sabotage your intentions.Here is how the issues we found directly impact the goals of your PR:1. Goal: Complete Process Isolation ("да не си пречат")• The Intent: Forking two separate processes so Activities and Opportunities index in parallelwithout blocking each other.The Reality Check: Because you are using pentl_fork(), the child processes inherit theparent's memory space and open file descriptors. While you correctly purged MySQL andRedis connections in resetAfterFork() . you missed the Elasticsearch client.The Result: Both the Activity process and the Opportunity process will attempt to read andwrite over the exact same HTTP/TCP socket to Elasticsearch simultaneously. Instead of notinterfering, they will literally collide at the network layer, causing corrupted payloads, CURLexceptions, and broken pipes.2. Goal: Reliable Signal Propagation & 10s Graceful ExitThe Intent: If the system (supervisorctl ) sends a SIGTERM, the customAsyncUpdateSupervisor catches it, propagates it to the children, and gracefully exits.The Reality Check: In your reapChildren() method, pcntl_waitpid($pid, Sstatus); ismissing the WNOHANG flag. This makes it a strictly synchronous, blocking call.The Result: If the Activity worker successfully receives the SIGTERM but gets stuck trying tofinish a stalled Elasticsearch request, the Parent Supervisor will block forever waiting for it. The10-second graceful exit logic in GracefullyStoppable will be completely ignored, andsupervisorctl will eventually have to forcefully SIGKILL the whole group, risking datauo.ion3. Goal: Accurate, Segregated Datadog MetricsThe Intent: Separating the Datadog reporting into ReindexTargetStatsReporter toXeerlewmescute metery dertruedAsk GeminiYour lim nou chate trhn" uend to imnroy our moddle Camioiie 4l1t cao mata mtake co donbls chack " Yoir oracy & CaminSummarize pagePull requests34Agents + Actions0 WikiSecurity and quality 12wInsights g SettingsA Vasil-Jiminny requested your review on this pull request.Jy 20910 schedule parallel update target processing #12130 •11 OpenVasil-Jiminny wants to merge 65 commits into naster from JY-28910-schedule-parallel-update-target-processingQ) Conversation 17a Commits 65E Checks 3 B Files changed 15Vasil-Jiminny commented 2 days ago • editedJIRA: JY-20910Changes:• Introduced a new class AsyncUpdateSupervisor under the same Artisan aliases:update-entities. The command works as parent / supervisor process and spawns a child process for eachallaued taradt tund o Mitrootly aetuity hodl onnnetunttvif a child process exits, the supervisor will restart it within 5 seconds.Ia SIGTERM is recerved, "willl oronsoste it to child orocesses.This allows each indexing operation to run with its own memory signature.• Cleanup old one-time commands that we do not need anymore.• Drop total memory usage, as it makes no sense when two separate processes are spawn for indexing activities andopportunities.• Improved GracefullyStoppable trait to correctly print exit message after 10 seconds.• Reporting Datadog metrics is moved to a separate class to keep concerns of UpdateProcessManager more strict.• Tests are uodated accoro-nolv• Added startup and exit logs.Startup Logs:SIGTERM logs:Highight All Match Case Match Diacriies Whoie Words1of 1 matchReached top of page, continued from bottomOESOMОД100% KSa- • Thu 28 May 14:40:02Q Type ( to search8 -• Awaiting approvaleode+764 -440 8887KOVICWUTIe vkulov@ LakyLak® TodorStamatovJiminnyilian-jiminnyyalokin-jiminnyAt least 1 approving review is required to merge this pullStill in progress? Convert to draftAssigneesNo ond=assion vourselLaoelsNone yetProjectsNonc wetMiles omNo milestoneDevelopmentSuccesstully merging this pull request may close theseIssue?None wetNotifications2 Unsubscribe...
|
84389
|
NULL
|
NULL
|
NULL
|
|
84391
|
2905
|
37
|
2026-05-28T11:40:02.757715+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968402757_m1.jpg...
|
Firefox
|
Meet - Lukas/Stefka 121 — Work
|
1
|
meet.google.com/axk-zwsm-vok?authuser=lukas.kovali meet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFile Edit→ViewGolHistoryWindowHelp> 0LA100 SlackFile Edit→ViewGolHistoryWindowHelp> 0LA100% C2Thu 28 May14:40:02meet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com1:57Are you still there?You're the only one here, so this call will end inless than 2 minutes. Do you want to stay inthis call?To stop seeing this, go to Settings > General.Leave now Stay in the callLukas Kovalik2:40 PM | Lukas/Stefka 121• 9:48...
|
NULL
|
6655171481010909567
|
NULL
|
click
|
ocr
|
NULL
|
SlackFile Edit→ViewGolHistoryWindowHelp> 0LA100 SlackFile Edit→ViewGolHistoryWindowHelp> 0LA100% C2Thu 28 May14:40:02meet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.com1:57Are you still there?You're the only one here, so this call will end inless than 2 minutes. Do you want to stay inthis call?To stop seeing this, go to Settings > General.Leave now Stay in the callLukas Kovalik2:40 PM | Lukas/Stefka 121• 9:48...
|
84390
|
NULL
|
NULL
|
NULL
|
|
84390
|
2905
|
36
|
2026-05-28T11:39:59.698864+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968399698_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageEmitsGaugeWhenLockIsAbsent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageSkipsGaugeWhenLockIsPresent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely, as the Redis lock and Datadog gauge logic were removed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Empty Selection Test:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
2736929145582772728
|
-3258990848001937276
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84389
|
2906
|
30
|
2026-05-28T11:39:56.437135+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968396437_m2.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.038065158,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.039893616,"top":0.0518755,"width":0.037898935,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"bounds":{"left":0.0028257978,"top":0.13288109,"width":0.03939495,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"bounds":{"left":0.0,"top":0.15203512,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.1632083,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"bounds":{"left":0.0028257978,"top":0.18994413,"width":0.020279255,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"bounds":{"left":0.0028257978,"top":0.21428572,"width":0.039228722,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.0028257978,"top":0.23782921,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.015957447,"top":0.2490024,"width":0.11402926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.27055067,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.28172386,"width":0.14245346,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"bounds":{"left":0.0,"top":0.30327216,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"bounds":{"left":0.013297873,"top":0.31444532,"width":0.030917553,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"bounds":{"left":0.0,"top":0.33599362,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"bounds":{"left":0.013297873,"top":0.3471668,"width":0.24301861,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"bounds":{"left":0.0,"top":0.36871508,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"bounds":{"left":0.013297873,"top":0.37988827,"width":0.09740692,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"bounds":{"left":0.0,"top":0.40143654,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.41260973,"width":0.08543883,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.43415803,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.44533122,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.4668795,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.47805268,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"bounds":{"left":0.0028257978,"top":0.5047885,"width":0.036070477,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.528332,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.5395052,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.56105345,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.57222664,"width":0.1271609,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.5937749,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.6049481,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.62649643,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.63766956,"width":0.12134308,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.6592179,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.6703911,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.69193935,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.70311254,"width":0.18201463,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.69912213,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.72625697,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"bounds":{"left":0.08228058,"top":0.09736632,"width":0.015957447,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"bounds":{"left":0.09823803,"top":0.10694334,"width":0.047539894,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"bounds":{"left":0.1022274,"top":0.10853951,"width":0.017121011,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"bounds":{"left":0.12084442,"top":0.10853951,"width":0.013796543,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"bounds":{"left":0.35854387,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"bounds":{"left":0.37051198,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"bounds":{"left":0.079288565,"top":0.14445332,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"bounds":{"left":0.079288565,"top":0.14684756,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
3666396556998798106
|
-3259026032374026108
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84388
|
2905
|
35
|
2026-05-28T11:39:53.454840+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968393454_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response
Bad response
Share & export
Copy
Show more options...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageEmitsGaugeWhenLockIsAbsent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageSkipsGaugeWhenLockIsPresent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely, as the Redis lock and Datadog gauge logic were removed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Empty Selection Test:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to verify that processing an empty selection logs a debug message, skips batch manager operations (","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), skips the stats reporter, and cleanly returns","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated Existing Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Modified","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunUpdate","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunDoUpdateButThrottled","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to assert that the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter->report()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method is called and to utilize the updated status manager mock.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Helper Method Refactoring","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Helper Method Refactoring","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Status Manager Assertions:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareStatusManager(int $invokeTimes = 0)","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to accept an integer. This allows tests to dynamically assert exactly how many times methods like","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are invoked.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Obsolete Helpers:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareLogger()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"silenceDatadogAndRedisLock()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"helper methods, replacing their inline functionality with standard","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Log::shouldReceive","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expectations where needed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":15,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-201985485679767272
|
-3403141220450930556
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response
Bad response
Share & export
Copy
Show more options...
|
84386
|
NULL
|
NULL
|
NULL
|
|
84387
|
2906
|
29
|
2026-05-28T11:39:40.797302+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968380797_m2.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.038065158,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.039893616,"top":0.0518755,"width":0.037898935,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"bounds":{"left":0.0028257978,"top":0.13288109,"width":0.03939495,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"bounds":{"left":0.0,"top":0.15203512,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.1632083,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"bounds":{"left":0.0028257978,"top":0.18994413,"width":0.020279255,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"bounds":{"left":0.0028257978,"top":0.21428572,"width":0.039228722,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.0028257978,"top":0.23782921,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.015957447,"top":0.2490024,"width":0.11402926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.27055067,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.28172386,"width":0.14245346,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"bounds":{"left":0.0,"top":0.30327216,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"bounds":{"left":0.013297873,"top":0.31444532,"width":0.030917553,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"bounds":{"left":0.0,"top":0.33599362,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"bounds":{"left":0.013297873,"top":0.3471668,"width":0.24301861,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"bounds":{"left":0.0,"top":0.36871508,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"bounds":{"left":0.013297873,"top":0.37988827,"width":0.09740692,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"bounds":{"left":0.0,"top":0.40143654,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.41260973,"width":0.08543883,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.43415803,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.44533122,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.4668795,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.47805268,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"bounds":{"left":0.0028257978,"top":0.5047885,"width":0.036070477,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.528332,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.5395052,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.56105345,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.57222664,"width":0.1271609,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.5937749,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.6049481,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.62649643,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.63766956,"width":0.12134308,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.6592179,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.6703911,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.69193935,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.70311254,"width":0.18201463,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.69912213,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.72625697,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"bounds":{"left":0.08228058,"top":0.09736632,"width":0.015957447,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"bounds":{"left":0.09823803,"top":0.10694334,"width":0.047539894,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"bounds":{"left":0.1022274,"top":0.10853951,"width":0.017121011,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"bounds":{"left":0.12084442,"top":0.10853951,"width":0.013796543,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"bounds":{"left":0.35854387,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"bounds":{"left":0.37051198,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"bounds":{"left":0.079288565,"top":0.14445332,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"bounds":{"left":0.079288565,"top":0.14684756,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageEmitsGaugeWhenLockIsAbsent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageSkipsGaugeWhenLockIsPresent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely, as the Redis lock and Datadog gauge logic were removed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Empty Selection Test:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-3656569021550646613
|
-3258990848001937276
|
idle
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse...
|
84385
|
NULL
|
NULL
|
NULL
|
|
84386
|
2905
|
34
|
2026-05-28T11:39:39.110997+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968379110_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"}]...
|
1209645535938855967
|
-3258463082420604796
|
idle
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84385
|
2906
|
28
|
2026-05-28T11:39:10.458207+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968350458_m2.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response
Bad response
Share & export
Copy
Show more options
You said find potential issues
You said
find potential issues
Copy prompt
Gemini said
Gemini said
Based on the provided git diff of...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.038065158,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.039893616,"top":0.0518755,"width":0.037898935,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"bounds":{"left":0.0028257978,"top":0.13288109,"width":0.03939495,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"bounds":{"left":0.0,"top":0.15203512,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.1632083,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"bounds":{"left":0.0028257978,"top":0.18994413,"width":0.020279255,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"bounds":{"left":0.0028257978,"top":0.21428572,"width":0.039228722,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.0028257978,"top":0.23782921,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.015957447,"top":0.2490024,"width":0.11402926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.27055067,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.28172386,"width":0.14245346,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"bounds":{"left":0.0,"top":0.30327216,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"bounds":{"left":0.013297873,"top":0.31444532,"width":0.030917553,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"bounds":{"left":0.0,"top":0.33599362,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"bounds":{"left":0.013297873,"top":0.3471668,"width":0.24301861,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"bounds":{"left":0.0,"top":0.36871508,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"bounds":{"left":0.013297873,"top":0.37988827,"width":0.09740692,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"bounds":{"left":0.0,"top":0.40143654,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.41260973,"width":0.08543883,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.43415803,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.44533122,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.4668795,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.47805268,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"bounds":{"left":0.0028257978,"top":0.5047885,"width":0.036070477,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.528332,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.5395052,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.56105345,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.57222664,"width":0.1271609,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.5937749,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.6049481,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.62649643,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.63766956,"width":0.12134308,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.6592179,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.6703911,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.69193935,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.70311254,"width":0.18201463,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.69912213,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.72625697,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"bounds":{"left":0.08228058,"top":0.09736632,"width":0.015957447,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"bounds":{"left":0.09823803,"top":0.10694334,"width":0.047539894,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"bounds":{"left":0.1022274,"top":0.10853951,"width":0.017121011,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"bounds":{"left":0.12084442,"top":0.10853951,"width":0.013796543,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"bounds":{"left":0.35854387,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"bounds":{"left":0.37051198,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"bounds":{"left":0.079288565,"top":0.14445332,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"bounds":{"left":0.079288565,"top":0.14684756,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageEmitsGaugeWhenLockIsAbsent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageSkipsGaugeWhenLockIsPresent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely, as the Redis lock and Datadog gauge logic were removed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Empty Selection Test:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to verify that processing an empty selection logs a debug message, skips batch manager operations (","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), skips the stats reporter, and cleanly returns","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated Existing Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Modified","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunUpdate","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunDoUpdateButThrottled","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to assert that the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter->report()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method is called and to utilize the updated status manager mock.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Helper Method Refactoring","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Helper Method Refactoring","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Status Manager Assertions:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareStatusManager(int $invokeTimes = 0)","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to accept an integer. This allows tests to dynamically assert exactly how many times methods like","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are invoked.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Obsolete Helpers:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareLogger()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"silenceDatadogAndRedisLock()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"helper methods, replacing their inline functionality with standard","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Log::shouldReceive","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expectations where needed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":15,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said find potential issues","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"find potential issues","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Based on the provided git diff of","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
1686485336414425049
|
-3114910844299218812
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response
Bad response
Share & export
Copy
Show more options
You said find potential issues
You said
find potential issues
Copy prompt
Gemini said
Gemini said
Based on the provided git diff of...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84384
|
2905
|
33
|
2026-05-28T11:39:08.808548+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968348808_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected....
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-2841637628066877512
|
-3403141220450930556
|
click
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected....
|
84382
|
NULL
|
NULL
|
NULL
|
|
84383
|
2906
|
27
|
2026-05-28T11:39:08.707477+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968348707_m2.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.038065158,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.039893616,"top":0.0518755,"width":0.037898935,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"bounds":{"left":0.0028257978,"top":0.13288109,"width":0.03939495,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"bounds":{"left":0.0,"top":0.15203512,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.1632083,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"bounds":{"left":0.0028257978,"top":0.18994413,"width":0.020279255,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"bounds":{"left":0.0028257978,"top":0.21428572,"width":0.039228722,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.0028257978,"top":0.23782921,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.015957447,"top":0.2490024,"width":0.11402926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.27055067,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.28172386,"width":0.14245346,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"bounds":{"left":0.0,"top":0.30327216,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"bounds":{"left":0.013297873,"top":0.31444532,"width":0.030917553,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"bounds":{"left":0.0,"top":0.33599362,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"bounds":{"left":0.013297873,"top":0.3471668,"width":0.24301861,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"bounds":{"left":0.0,"top":0.36871508,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"bounds":{"left":0.013297873,"top":0.37988827,"width":0.09740692,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"bounds":{"left":0.0,"top":0.40143654,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.41260973,"width":0.08543883,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.43415803,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.44533122,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.4668795,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.47805268,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"bounds":{"left":0.0028257978,"top":0.5047885,"width":0.036070477,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.528332,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.5395052,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.56105345,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.57222664,"width":0.1271609,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.5937749,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.6049481,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.62649643,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.63766956,"width":0.12134308,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.6592179,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.6703911,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.69193935,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.70311254,"width":0.18201463,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.69912213,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.72625697,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"bounds":{"left":0.08228058,"top":0.09736632,"width":0.015957447,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"bounds":{"left":0.09823803,"top":0.10694334,"width":0.047539894,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"bounds":{"left":0.1022274,"top":0.10853951,"width":0.017121011,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"bounds":{"left":0.12084442,"top":0.10853951,"width":0.013796543,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"bounds":{"left":0.35854387,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"bounds":{"left":0.37051198,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"bounds":{"left":0.079288565,"top":0.14445332,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"bounds":{"left":0.079288565,"top":0.14684756,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageEmitsGaugeWhenLockIsAbsent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageSkipsGaugeWhenLockIsPresent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely, as the Redis lock and Datadog gauge logic were removed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Empty Selection Test:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to verify that processing an empty selection logs a debug message, skips batch manager operations (","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), skips the stats reporter, and cleanly returns","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated Existing Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Modified","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunUpdate","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunDoUpdateButThrottled","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to assert that the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter->report()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method is called and to utilize the updated status manager mock.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Helper Method Refactoring","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Helper Method Refactoring","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Status Manager Assertions:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareStatusManager(int $invokeTimes = 0)","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to accept an integer. This allows tests to dynamically assert exactly how many times methods like","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are invoked.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Obsolete Helpers:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareLogger()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"silenceDatadogAndRedisLock()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"helper methods, replacing their inline functionality with standard","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Log::shouldReceive","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expectations where needed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
8714041469178156766
|
-3114347894345797500
|
click
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response...
|
84379
|
NULL
|
NULL
|
NULL
|
|
84382
|
2905
|
32
|
2026-05-28T11:39:04.430569+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968344430_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response
Bad response
Share & export
Copy
Show more options
You said find potential issues
You said
find potential issues
Copy prompt
Gemini said
Gemini said
Based on the provided git diff of
UpdateProcessManagerTest.php
, here are the potential issues, risks, and improvements identified in the changes:
1. Missing setUpdateTarget Expectation in testEmptySelectionLogsAndReturnsFalse...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageEmitsGaugeWhenLockIsAbsent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageSkipsGaugeWhenLockIsPresent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely, as the Redis lock and Datadog gauge logic were removed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Empty Selection Test:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to verify that processing an empty selection logs a debug message, skips batch manager operations (","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), skips the stats reporter, and cleanly returns","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated Existing Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Modified","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunUpdate","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunDoUpdateButThrottled","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to assert that the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter->report()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method is called and to utilize the updated status manager mock.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Helper Method Refactoring","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Helper Method Refactoring","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Status Manager Assertions:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareStatusManager(int $invokeTimes = 0)","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to accept an integer. This allows tests to dynamically assert exactly how many times methods like","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are invoked.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Obsolete Helpers:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareLogger()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"silenceDatadogAndRedisLock()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"helper methods, replacing their inline functionality with standard","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Log::shouldReceive","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expectations where needed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":15,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said find potential issues","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"find potential issues","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Based on the provided git diff of","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", here are the potential issues, risks, and improvements identified in the changes:","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Missing setUpdateTarget Expectation in testEmptySelectionLogsAndReturnsFalse","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"}]...
|
-4780125253773054477
|
-3114347894345797500
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response
Bad response
Share & export
Copy
Show more options
You said find potential issues
You said
find potential issues
Copy prompt
Gemini said
Gemini said
Based on the provided git diff of
UpdateProcessManagerTest.php
, here are the potential issues, risks, and improvements identified in the changes:
1. Missing setUpdateTarget Expectation in testEmptySelectionLogsAndReturnsFalse...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84381
|
2905
|
31
|
2026-05-28T11:39:01.229288+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968341229_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
6084179770924766573
|
-3259026032374026108
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:...
|
84380
|
NULL
|
NULL
|
NULL
|
|
84380
|
2905
|
30
|
2026-05-28T11:38:57.727271+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968337727_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response
Bad response
Share & export
Copy
Show more options
You said find potential issues
You said
find potential issues
Copy prompt
Gemini said
Gemini said
Based on the provided git diff of
UpdateProcessManagerTest.php
, here are the potential issues, risks, and improvements identified in the changes:
1. Missing setUpdateTarget Expectation in testEmptySelectionLogsAndReturnsFalse
1. Missing
setUpdateTarget
Expectation in
testEmptySelectionLogsAndReturnsFalse
In the newly added test
testEmptySelectionLogsAndReturnsFalse
, you explicitly mock the
BatchStatusManager
and set an expectation for
setUpdateTarget
:
PHP
Download code
Copy code
$batchStatusManager
->expects(
$this
->once())->method(
'setUpdateTarget'
)->with(
self
::UPDATE_TARGET);
However, later in the same test, you instantiate
UpdateProcessManager
manually and explicitly call:
PHP
Download code
Copy code
$processor
->setUpdateTarget(
self
::UPDATE_TARGET);...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageEmitsGaugeWhenLockIsAbsent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageSkipsGaugeWhenLockIsPresent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely, as the Redis lock and Datadog gauge logic were removed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Empty Selection Test:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to verify that processing an empty selection logs a debug message, skips batch manager operations (","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), skips the stats reporter, and cleanly returns","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated Existing Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Modified","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunUpdate","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunDoUpdateButThrottled","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to assert that the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter->report()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method is called and to utilize the updated status manager mock.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Helper Method Refactoring","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Helper Method Refactoring","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Status Manager Assertions:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareStatusManager(int $invokeTimes = 0)","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to accept an integer. This allows tests to dynamically assert exactly how many times methods like","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are invoked.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Obsolete Helpers:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareLogger()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"silenceDatadogAndRedisLock()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"helper methods, replacing their inline functionality with standard","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Log::shouldReceive","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expectations where needed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":15,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said find potential issues","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"find potential issues","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Based on the provided git diff of","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", here are the potential issues, risks, and improvements identified in the changes:","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Missing setUpdateTarget Expectation in testEmptySelectionLogsAndReturnsFalse","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Missing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expectation in","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In the newly added test","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", you explicitly mock the","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BatchStatusManager","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and set an expectation for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PHP","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Download code","depth":18,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy code","depth":18,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"$batchStatusManager","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->expects(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->once())->method(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'setUpdateTarget'","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")->with(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"self","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"::UPDATE_TARGET);","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However, later in the same test, you instantiate","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"manually and explicitly call:","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PHP","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Download code","depth":18,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy code","depth":18,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"$processor","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->setUpdateTarget(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"self","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"::UPDATE_TARGET);","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-268903553658805889
|
-3114347894345797500
|
click
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response
Bad response
Share & export
Copy
Show more options
You said find potential issues
You said
find potential issues
Copy prompt
Gemini said
Gemini said
Based on the provided git diff of
UpdateProcessManagerTest.php
, here are the potential issues, risks, and improvements identified in the changes:
1. Missing setUpdateTarget Expectation in testEmptySelectionLogsAndReturnsFalse
1. Missing
setUpdateTarget
Expectation in
testEmptySelectionLogsAndReturnsFalse
In the newly added test
testEmptySelectionLogsAndReturnsFalse
, you explicitly mock the
BatchStatusManager
and set an expectation for
setUpdateTarget
:
PHP
Download code
Copy code
$batchStatusManager
->expects(
$this
->once())->method(
'setUpdateTarget'
)->with(
self
::UPDATE_TARGET);
However, later in the same test, you instantiate
UpdateProcessManager
manually and explicitly call:
PHP
Download code
Copy code
$processor
->setUpdateTarget(
self
::UPDATE_TARGET);...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84379
|
2906
|
26
|
2026-05-28T11:38:57.622231+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968337622_m2.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.038065158,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.039893616,"top":0.0518755,"width":0.037898935,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"bounds":{"left":0.0028257978,"top":0.13288109,"width":0.03939495,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"bounds":{"left":0.0,"top":0.15203512,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.1632083,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"bounds":{"left":0.0028257978,"top":0.18994413,"width":0.020279255,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"bounds":{"left":0.0028257978,"top":0.21428572,"width":0.039228722,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.0028257978,"top":0.23782921,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.015957447,"top":0.2490024,"width":0.11402926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.27055067,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.28172386,"width":0.14245346,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"bounds":{"left":0.0,"top":0.30327216,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"bounds":{"left":0.013297873,"top":0.31444532,"width":0.030917553,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"bounds":{"left":0.0,"top":0.33599362,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"bounds":{"left":0.013297873,"top":0.3471668,"width":0.24301861,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"bounds":{"left":0.0,"top":0.36871508,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"bounds":{"left":0.013297873,"top":0.37988827,"width":0.09740692,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"bounds":{"left":0.0,"top":0.40143654,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.41260973,"width":0.08543883,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.43415803,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.44533122,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.4668795,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.47805268,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"bounds":{"left":0.0028257978,"top":0.5047885,"width":0.036070477,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.528332,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.5395052,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.56105345,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.57222664,"width":0.1271609,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.5937749,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.6049481,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.62649643,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.63766956,"width":0.12134308,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.6592179,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.6703911,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.69193935,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.70311254,"width":0.18201463,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.69912213,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.72625697,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"bounds":{"left":0.08228058,"top":0.09736632,"width":0.015957447,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"bounds":{"left":0.09823803,"top":0.10694334,"width":0.047539894,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"bounds":{"left":0.1022274,"top":0.10853951,"width":0.017121011,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"bounds":{"left":0.12084442,"top":0.10853951,"width":0.013796543,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"bounds":{"left":0.35854387,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"bounds":{"left":0.37051198,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"bounds":{"left":0.079288565,"top":0.14445332,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"bounds":{"left":0.079288565,"top":0.14684756,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4636916507127959455
|
-3259026032374026108
|
click
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84378
|
2905
|
29
|
2026-05-28T11:38:51.536582+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968331536_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant....
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
6710077951610244591
|
-3259026032374026108
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant....
|
84377
|
NULL
|
NULL
|
NULL
|
|
84377
|
2905
|
28
|
2026-05-28T11:38:49.846840+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968329846_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageEmitsGaugeWhenLockIsAbsent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageSkipsGaugeWhenLockIsPresent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely, as the Redis lock and Datadog gauge logic were removed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Empty Selection Test:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to verify that processing an empty selection logs a debug message, skips batch manager operations (","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), skips the stats reporter, and cleanly returns","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated Existing Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Modified","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunUpdate","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunDoUpdateButThrottled","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to assert that the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter->report()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method is called and to utilize the updated status manager mock.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Helper Method Refactoring","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Helper Method Refactoring","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Status Manager Assertions:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareStatusManager(int $invokeTimes = 0)","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to accept an integer. This allows tests to dynamically assert exactly how many times methods like","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-3569724466976045071
|
-3402578270496460668
|
typing_pause
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84376
|
2906
|
25
|
2026-05-28T11:38:49.650968+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968329650_m2.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.038065158,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.039893616,"top":0.0518755,"width":0.037898935,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"bounds":{"left":0.0028257978,"top":0.13288109,"width":0.03939495,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"bounds":{"left":0.0,"top":0.15203512,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.1632083,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"bounds":{"left":0.0028257978,"top":0.18994413,"width":0.020279255,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"bounds":{"left":0.0028257978,"top":0.21428572,"width":0.039228722,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.0028257978,"top":0.23782921,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.015957447,"top":0.2490024,"width":0.11402926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.27055067,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.28172386,"width":0.14245346,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"bounds":{"left":0.0,"top":0.30327216,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"bounds":{"left":0.013297873,"top":0.31444532,"width":0.030917553,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"bounds":{"left":0.0,"top":0.33599362,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"bounds":{"left":0.013297873,"top":0.3471668,"width":0.24301861,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"bounds":{"left":0.0,"top":0.36871508,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"bounds":{"left":0.013297873,"top":0.37988827,"width":0.09740692,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"bounds":{"left":0.0,"top":0.40143654,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.41260973,"width":0.08543883,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.43415803,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.44533122,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.4668795,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.47805268,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"bounds":{"left":0.0028257978,"top":0.5047885,"width":0.036070477,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.528332,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.5395052,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.56105345,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.57222664,"width":0.1271609,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.5937749,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.6049481,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.62649643,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.63766956,"width":0.12134308,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.6592179,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.6703911,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.69193935,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.70311254,"width":0.18201463,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.69912213,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.72625697,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"bounds":{"left":0.08228058,"top":0.09736632,"width":0.015957447,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"bounds":{"left":0.09823803,"top":0.10694334,"width":0.047539894,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"bounds":{"left":0.1022274,"top":0.10853951,"width":0.017121011,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"bounds":{"left":0.12084442,"top":0.10853951,"width":0.013796543,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"bounds":{"left":0.35854387,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"bounds":{"left":0.37051198,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"bounds":{"left":0.079288565,"top":0.14445332,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"bounds":{"left":0.079288565,"top":0.14684756,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-5954009690915080277
|
-3259026032374026076
|
typing_pause
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand...
|
84375
|
NULL
|
NULL
|
NULL
|
|
84375
|
2906
|
24
|
2026-05-28T11:38:48.566028+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968328566_m2.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.038065158,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.039893616,"top":0.0518755,"width":0.037898935,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"bounds":{"left":0.0028257978,"top":0.13288109,"width":0.03939495,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"bounds":{"left":0.0,"top":0.15203512,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.1632083,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"bounds":{"left":0.0028257978,"top":0.18994413,"width":0.020279255,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"bounds":{"left":0.0028257978,"top":0.21428572,"width":0.039228722,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.0028257978,"top":0.23782921,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.015957447,"top":0.2490024,"width":0.11402926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.27055067,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.28172386,"width":0.14245346,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"bounds":{"left":0.0,"top":0.30327216,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"bounds":{"left":0.013297873,"top":0.31444532,"width":0.030917553,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"bounds":{"left":0.0,"top":0.33599362,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"bounds":{"left":0.013297873,"top":0.3471668,"width":0.24301861,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"bounds":{"left":0.0,"top":0.36871508,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"bounds":{"left":0.013297873,"top":0.37988827,"width":0.09740692,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"bounds":{"left":0.0,"top":0.40143654,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.41260973,"width":0.08543883,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.43415803,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.44533122,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.4668795,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.47805268,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"bounds":{"left":0.0028257978,"top":0.5047885,"width":0.036070477,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.528332,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.5395052,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.56105345,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.57222664,"width":0.1271609,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.5937749,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.6049481,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.62649643,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.63766956,"width":0.12134308,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.6592179,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.6703911,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.69193935,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.70311254,"width":0.18201463,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.69912213,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.72625697,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"bounds":{"left":0.08228058,"top":0.09736632,"width":0.015957447,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"bounds":{"left":0.09823803,"top":0.10694334,"width":0.047539894,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"bounds":{"left":0.1022274,"top":0.10853951,"width":0.017121011,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"bounds":{"left":0.12084442,"top":0.10853951,"width":0.013796543,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"bounds":{"left":0.35854387,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"bounds":{"left":0.37051198,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"bounds":{"left":0.079288565,"top":0.14445332,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"bounds":{"left":0.079288565,"top":0.14684756,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
4919951009979970015
|
-3259026032374026108
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84373
|
2905
|
27
|
2026-05-28T11:38:47.865769+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968327865_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy....
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"}]...
|
1717921840857720572
|
-3393641439985897308
|
click
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy....
|
84370
|
NULL
|
NULL
|
NULL
|
|
84374
|
2906
|
23
|
2026-05-28T11:38:47.187958+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968327187_m2.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 2 new items - S Vasil Vasilev (DM) - Jiminny Inc - 2 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":6,"bounds":{"left":0.5056516,"top":0.058260176,"width":0.011968086,"height":0.028731046},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":6,"bounds":{"left":0.50299203,"top":0.10055866,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":8,"bounds":{"left":0.50664896,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":6,"bounds":{"left":0.50299203,"top":0.15482841,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":8,"bounds":{"left":0.50764626,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":6,"bounds":{"left":0.50299203,"top":0.20909816,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-254204207111190222
|
-8120670020800660841
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
SluCkcolVIChRotonWindowHelp= github.com/jiminny/app/pull/12130v Gooc e Gemini© Pipelines - |IminnylappGemini 3.1 Pro ~* (JY-20613) Allow owner's role to txUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jiminoonye Rosd ve php 81.15 dedPlatform Sorint 5.02 - Platform Te8 Jiminny7 (SRD-6881] (On demand) TransSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XRedis::set(SlockKey, true);kedws..expirelslockkey, setrt:loek_ffL-seconds);The Issue & Explanation:This PR extracts the metric logging into a new ReindexTargetStatsReporter class. Because thissystem now uses a multi-process worker model (thanks to the new Supervisor), multiple childprocesses can hit this block at the exact same microsecond.Process A and Process B both call Redis: :get (SlockKey) . Both receive null . Both then proceedto call Redis:: set (...) and push duplicate memory and queue size metrics to Datadog. Thisdefeats the purpose of the lock.The Fix: Use a single atomic Redis command. Redis: : set (SlockKey, true, 'EX',self::LOCK_TTL_SECONDS,"NX") will only set the key if it doesn't exist, returning false ifanother process beat it to the punch.4. Corrupted Stop Signal State on Exception (Logic Flaw)File Introduced in PR: app/Component/ES/EntityTypeReindexer.phpThe toroPHPSstopSignal->markSafeToStop(false);ShasWork = Sthis->updateProcessManager->doUpdateEntitiesChunk);SstopSignal->markSafeToStop(true);Improved GracefullyStoppable trait to correctly print exit message after 10seconds.Renortine Datadoa metrics is moved to a senarate class to keen concerns ofiUpdateProcessManager more strict.Tests are updated accordingly.Added startup and exit logs.ano aso snor exo anaton<> Codejiminny / app &17 Pull requests 34G. AgeHomeDMsActivityLaterMoreYour lim nou chate trhn" uend to imnroy our moddle Camioiie 4l1t cao mata mtake co donbls chack " Yoir oracy & CaminSummarize pageJiminnY …simackend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday8 infosec.intemal.all# infra-changes# infrastructure de# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product launches# random# releases# support# thank-yous# the_people_of_jimi…^ Direct messagesGo Vasil Vasilev •Stoyan TomovQ. lliyana Netseva8?. Petko Kashinski(D. Galya Dimitrova Eff. Stefka Stoyanova. Todor StamatovR. Steliyan Georgiev8. Ves(R. MiraPP. Nikolay Yankovd. James Graham22. Lukas Kovalik y-#: Apps6 Jira Cloud• Toast@ Google Cale...Thu 28 May 14:38:46Q Describe what you are looking for€o Vasil Vasilev *e MessagerNoR0d canvis© Filesне знам дали го ползваш, но е много полезен туулUCoNyMayyuVasil Vasilev Ol 9:18 AMДобро утро, Лукашкогато имаш днес възможностмоля те поглелни тоя ПРhttos:github.com/uminnv/apo/oulla1408%Yasi Washley 1029 AMTodayukas Kovalk Teздрасти Васко, може ли един approve https://github.com/jiminny/app/pull/12136Vasil Vasilev ©! 12:00 PMЗдрасти, Лукашготов сималко по косно и на мен ще ми тояова осню зи слин голям тенкuгьно ще ти пиша, като с готов за гледане (edited)Lukas Kovalik 12:11PMav mardVasil Vasilev ® 1:23 PMкато имаш време, разгледай този интересен ПР. https://github.com/jiminny/app/pull/12130Message Vasil Vasilev Lunch time...
|
84372
|
NULL
|
NULL
|
NULL
|
|
84372
|
2906
|
22
|
2026-05-28T11:38:44.998820+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968324998_m2.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 2 new items - S Vasil Vasilev (DM) - Jiminny Inc - 2 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
platform-backend-engineers
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
donut_time
engineering
general
happy_birthday
infosec_internal_all
infra-changes
infrastructure_dev
jbu-team-info
jiminny-bg
platform-team
platform-tickets
product_launches
random
releases
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Stoyan Tomov
Iliyana Netseva
Petko Kashinski
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Steliyan Georgiev
Ves
Mira
Nikolay Yankov
James Graham
Lukas Kovalik
you
Jira Cloud
Toast
Google Calendar
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Vasil Vasilev
May 18th at 10:17:38 AM
10:17 AM
Лукаш, привет
(edited)
May 18th at 10:17:59 AM
10:17
трябват ми няколко ревюта за разни ЕС промени
May 18th at 10:18:09 AM
10:18
разделени са на относително малки части
May 18th at 10:18:09 AM
10:18
https://github.com/jiminny/app/pull/12086
https://github.com/jiminny/app/pull/12086
May 18th at 10:18:17 AM
10:18
https://github.com/jiminny/app/pull/12088/changes
https://github.com/jiminny/app/pull/12088/changes
Vasil Vasilev
May 18th at 10:38:52 AM
10:38 AM
благодаря
Lukas Kovalik
May 18th at 10:39:26 AM
10:39 AM
готово
(edited)
Vasil Vasilev
May 18th at 10:39:33 AM
10:39 AM
видях
May 18th at 10:39:42 AM
10:39
получавам в slack нотификации от toast
(edited)
Lukas Kovalik
May 18th at 10:39:57 AM
10:39 AM
a da
Vasil Vasilev...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":6,"bounds":{"left":0.5056516,"top":0.058260176,"width":0.011968086,"height":0.028731046},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":6,"bounds":{"left":0.50299203,"top":0.10055866,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":8,"bounds":{"left":0.50664896,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":6,"bounds":{"left":0.50299203,"top":0.15482841,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":8,"bounds":{"left":0.50764626,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":6,"bounds":{"left":0.50299203,"top":0.20909816,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":8,"bounds":{"left":0.5053192,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5053192,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.50764626,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":6,"bounds":{"left":0.50299203,"top":0.26336792,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":8,"bounds":{"left":0.50797874,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.50797874,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.5099734,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":6,"bounds":{"left":0.50299203,"top":0.31763768,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":8,"bounds":{"left":0.50731385,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.50731385,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.5093085,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":6,"bounds":{"left":0.50299203,"top":0.3719074,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":8,"bounds":{"left":0.50731385,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.50731385,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.5106383,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-backend-engineers","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":15,"bounds":{"left":0.5422208,"top":0.096568234,"width":0.018284574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.096568234,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.54521275,"top":0.096568234,"width":0.015292553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":15,"bounds":{"left":0.5422208,"top":0.118914604,"width":0.010638298,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.118914604,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.54521275,"top":0.118914604,"width":0.00731383,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":15,"bounds":{"left":0.5422208,"top":0.14126097,"width":0.034574468,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.14126097,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.54454786,"top":0.14126097,"width":0.032247342,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"donut_time","depth":15,"bounds":{"left":0.5422208,"top":0.16360734,"width":0.025265958,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.16360734,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.54521275,"top":0.16360734,"width":0.022273935,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":15,"bounds":{"left":0.5422208,"top":0.1859537,"width":0.025930852,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.1859537,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.54488033,"top":0.1859537,"width":0.022938829,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"general","depth":15,"bounds":{"left":0.5422208,"top":0.20830008,"width":0.016289894,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.20830008,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.54488033,"top":0.20830008,"width":0.013297873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":15,"bounds":{"left":0.5422208,"top":0.23064645,"width":0.033909574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.23064645,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.54521275,"top":0.23064645,"width":0.030917553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"infosec_internal_all","depth":15,"bounds":{"left":0.5422208,"top":0.2529928,"width":0.041888297,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.2529928,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":19,"bounds":{"left":0.54355055,"top":0.2529928,"width":0.040226065,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"infra-changes","depth":15,"bounds":{"left":0.5422208,"top":0.2753392,"width":0.029587766,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.2753392,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.54355055,"top":0.2753392,"width":0.02825798,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"infrastructure_dev","depth":15,"bounds":{"left":0.5422208,"top":0.29768556,"width":0.040226065,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.29768556,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":17,"bounds":{"left":0.54355055,"top":0.29768556,"width":0.038896278,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jbu-team-info","depth":15,"bounds":{"left":0.5422208,"top":0.3200319,"width":0.029920213,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.3200319,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.54355055,"top":0.3200319,"width":0.028590426,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":15,"bounds":{"left":0.5422208,"top":0.3423783,"width":0.023271276,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.3423783,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.54355055,"top":0.3423783,"width":0.021609042,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-team","depth":15,"bounds":{"left":0.5422208,"top":0.36472467,"width":0.03158245,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.36472467,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.54521275,"top":0.36472467,"width":0.028590426,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":15,"bounds":{"left":0.5422208,"top":0.38707104,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.38707104,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.54521275,"top":0.38707104,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":15,"bounds":{"left":0.5422208,"top":0.4094174,"width":0.03856383,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.4094174,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.54521275,"top":0.4094174,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"random","depth":15,"bounds":{"left":0.5422208,"top":0.43176377,"width":0.016954787,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.43176377,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.54421544,"top":0.43176377,"width":0.014960106,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":15,"bounds":{"left":0.5422208,"top":0.45411015,"width":0.01761968,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.45411015,"width":0.0016622341,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.54388297,"top":0.45411015,"width":0.015957447,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":15,"bounds":{"left":0.5422208,"top":0.4764565,"width":0.017287234,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.4764565,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.54454786,"top":0.4764565,"width":0.01462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":15,"bounds":{"left":0.5422208,"top":0.49880287,"width":0.024601065,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.49880287,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.54421544,"top":0.49880287,"width":0.022606382,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":15,"bounds":{"left":0.5422208,"top":0.5211492,"width":0.045212764,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.5211492,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":20,"bounds":{"left":0.54421544,"top":0.5211492,"width":0.04720745,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":15,"bounds":{"left":0.5422208,"top":0.5738228,"width":0.026595745,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.5738228,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.54521275,"top":0.5738228,"width":0.023271276,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":15,"bounds":{"left":0.5422208,"top":0.5961692,"width":0.030917553,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.5961692,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.54488033,"top":0.5961692,"width":0.027925532,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Iliyana Netseva","depth":15,"bounds":{"left":0.5422208,"top":0.61851555,"width":0.03324468,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.61851555,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.54355055,"top":0.61851555,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":15,"bounds":{"left":0.5422208,"top":0.6408619,"width":0.034574468,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.6408619,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.54521275,"top":0.6408619,"width":0.03158245,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":15,"bounds":{"left":0.5422208,"top":0.6632083,"width":0.03523936,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.6632083,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.54587764,"top":0.6632083,"width":0.03158245,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":15,"bounds":{"left":0.5422208,"top":0.6855547,"width":0.037898935,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.6855547,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.54488033,"top":0.6855547,"width":0.03523936,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":15,"bounds":{"left":0.5422208,"top":0.70790106,"width":0.034574468,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.70790106,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.54454786,"top":0.70790106,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":15,"bounds":{"left":0.5422208,"top":0.7302474,"width":0.038231384,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.7302474,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":16,"bounds":{"left":0.54488033,"top":0.7302474,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":15,"bounds":{"left":0.5422208,"top":0.75259376,"width":0.007978723,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.75259376,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.54521275,"top":0.75259376,"width":0.004986702,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Mira","depth":15,"bounds":{"left":0.5422208,"top":0.77494013,"width":0.010305851,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.77494013,"width":0.004654255,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.546875,"top":0.77494013,"width":0.005319149,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":15,"bounds":{"left":0.5422208,"top":0.7972865,"width":0.032912236,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.7972865,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.5462101,"top":0.7972865,"width":0.028922873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":15,"bounds":{"left":0.5422208,"top":0.8196329,"width":0.031914894,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.8196329,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.54421544,"top":0.8196329,"width":0.029920213,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":15,"bounds":{"left":0.5422208,"top":0.84197927,"width":0.029587766,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.84197927,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.54488033,"top":0.84197927,"width":0.026928192,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"you","depth":15,"bounds":{"left":0.5744681,"top":0.84197927,"width":0.0063164895,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5744681,"top":0.84197927,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.5767952,"top":0.84197927,"width":0.0056515955,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":15,"bounds":{"left":0.5422208,"top":0.89465284,"width":0.021941489,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.89465284,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.54421544,"top":0.89465284,"width":0.019946808,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":15,"bounds":{"left":0.5422208,"top":0.9169992,"width":0.011635638,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.9169992,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":4,"bounds":{"left":0.54454786,"top":0.9169992,"width":0.00930851,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Google Calendar","depth":15,"bounds":{"left":0.5422208,"top":0.9393456,"width":0.030585106,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.9393456,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.54587764,"top":0.9393456,"width":0.032912236,"height":0.014365523}}],"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":9,"bounds":{"left":0.60206115,"top":0.09177973,"width":0.030917553,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":11,"bounds":{"left":0.61136967,"top":0.10055866,"width":0.018949468,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.61136967,"top":0.10055866,"width":0.0039893617,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.61535907,"top":0.10055866,"width":0.014960106,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":10,"bounds":{"left":0.63397604,"top":0.09177973,"width":0.034242023,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":12,"bounds":{"left":0.64328456,"top":0.10055866,"width":0.022273935,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.64328456,"top":0.10055866,"width":0.0033244682,"height":0.012769354}},{"char_start":1,"char_count":9,"bounds":{"left":0.6462766,"top":0.10055866,"width":0.019281914,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":9,"bounds":{"left":0.66921544,"top":0.09177973,"width":0.020944148,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":11,"bounds":{"left":0.67852396,"top":0.10055866,"width":0.008976064,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":9,"bounds":{"left":0.69148934,"top":0.09177973,"width":0.020279255,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":11,"bounds":{"left":0.70079786,"top":0.10055866,"width":0.00831117,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":9,"bounds":{"left":0.71276593,"top":0.09177973,"width":0.010970744,"height":0.030327214},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":9,"bounds":{"left":0.59640956,"top":0.0518755,"width":0.015957447,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":9,"bounds":{"left":0.59640956,"top":0.0518755,"width":0.007978723,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":9,"bounds":{"left":0.59640956,"top":0.0518755,"width":0.013962766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":15,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:17:38 AM","depth":15,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:17 AM","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:17:59 AM","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:17","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"трябват ми няколко ревюта за разни ЕС промени","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:18:09 AM","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:18","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"разделени са на относително малки части","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:18:09 AM","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:18","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12086","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12086","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:18:17 AM","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:18","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12088/changes","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12088/changes","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":15,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:38:52 AM","depth":15,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:38 AM","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"благодаря","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":15,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:39:26 AM","depth":15,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:39 AM","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"готово","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":15,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:39:33 AM","depth":15,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:39 AM","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"видях","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:39:42 AM","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:39","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"получавам в slack нотификации от toast","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":15,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:39:57 AM","depth":15,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:39 AM","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"a da","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":15,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":15,"on_screen":false,"role_description":"text"}]...
|
5803517405989610450
|
-1281284622486684498
|
visual_change
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
platform-backend-engineers
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
donut_time
engineering
general
happy_birthday
infosec_internal_all
infra-changes
infrastructure_dev
jbu-team-info
jiminny-bg
platform-team
platform-tickets
product_launches
random
releases
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Stoyan Tomov
Iliyana Netseva
Petko Kashinski
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Steliyan Georgiev
Ves
Mira
Nikolay Yankov
James Graham
Lukas Kovalik
you
Jira Cloud
Toast
Google Calendar
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Vasil Vasilev
May 18th at 10:17:38 AM
10:17 AM
Лукаш, привет
(edited)
May 18th at 10:17:59 AM
10:17
трябват ми няколко ревюта за разни ЕС промени
May 18th at 10:18:09 AM
10:18
разделени са на относително малки части
May 18th at 10:18:09 AM
10:18
https://github.com/jiminny/app/pull/12086
https://github.com/jiminny/app/pull/12086
May 18th at 10:18:17 AM
10:18
https://github.com/jiminny/app/pull/12088/changes
https://github.com/jiminny/app/pull/12088/changes
Vasil Vasilev
May 18th at 10:38:52 AM
10:38 AM
благодаря
Lukas Kovalik
May 18th at 10:39:26 AM
10:39 AM
готово
(edited)
Vasil Vasilev
May 18th at 10:39:33 AM
10:39 AM
видях
May 18th at 10:39:42 AM
10:39
получавам в slack нотификации от toast
(edited)
Lukas Kovalik
May 18th at 10:39:57 AM
10:39 AM
a da
Vasil Vasilev
SluCkcolVIChRotonWindowHelp= github.com/jiminny/app/pull/12130v Gooc e Gemini© Pipelines - |IminnylappGemini 3.1 Pro ~* (JY-20613) Allow owner's role to txUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jiminoonye Rosd ve php 81.15 dedPlatform Sorint 5.02 - Platform Te8 Jiminny7 (SRD-6881] (On demand) TransSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XRedis::set(SlockKey, true);kedws..expirelslockkey, setrt:loek_ffL-seconds);The Issue & Explanation:This PR extracts the metric logging into a new ReindexTargetStatsReporter class. Because thissystem now uses a multi-process worker model (thanks to the new Supervisor), multiple childprocesses can hit this block at the exact same microsecond.Process A and Process B both call Redis: :get (SlockKey) . Both receive null . Both then proceedto call Redis:: set (...) and push duplicate memory and queue size metrics to Datadog. Thisdefeats the purpose of the lock.The Fix: Use a single atomic Redis command. Redis: : set (SlockKey, true, 'EX',self::LOCK_TTL_SECONDS,"NX") will only set the key if it doesn't exist, returning false ifanother process beat it to the punch.4. Corrupted Stop Signal State on Exception (Logic Flaw)File Introduced in PR: app/Component/ES/EntityTypeReindexer.phpThe toroPHPSstopSignal->markSafeToStop(false);ShasWork = Sthis->updateProcessManager->doUpdateEntitiesChunk();SstopSignal->markSafeToStop(true);Improved GracefullyStoppable trait to correctly print exit message after 10seconds.Renortine Datadoa metrics is moved to a senarate class to keen concerns ofiUpdateProcessManager more strict.Tests are updated accordingly.Added startup and exit logs.ano aso snor exo anaton<> Codejiminny / app 817 Pull requests 34G. AgeHomeDMsActivityLaterMoreYour lim nou chate trhn" uend to imnroy our moddle Camioiie 4l1t cao mata mtake co donbls chack " Yoir oracy & CaminSummarize pageJiminnY ….simackend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday8 infosec.intemal.all# infra-changes# infrastructure de# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product lunches# random# releases# support# thank-yous# the_people_of jim..^ Direct messagesGo Vasil Vasilev •Stoyan TomovQ. lliyana Netseva8?. Petko Kashinski(D. Galya Dimitrova Eff. Stefka Stoyanova. Todor StamatovR. Steliyan Georgiev8. Ves(R. MiraPP. Nikolay Yankov4. James Graham2. Lukas Kovvalik .....#: Apps6 Jira Cloud• Toast@ Google Cale...Ino cowoy 14.50.4Q Describe what you are looking for€. Vasil Vasilev •e MessagerNoR0d canvis© Filesне знам дали го ползваш, но е много полезен туулUCoNyMayyuVasil Vasilev Ol 9:18 AMДобро утро, Лукашкогато имаш днес възможностмоля те поглелни тоя ПРhttps://github.com/jiminny/app/pull/12082Yasi Washley 1029 AMTodaykas Kovallk tessздрасти Васко, може ли един approve https://github.com/jiminny/app/pull/12136Vasil Vasilev ©! 12:00 PMЗдрасти, Лукашготов сималко по косно и на мен ще ми тояова осню зи слин голям тенкuгьно ще ти пиша, като с готов за гледане (edited)Lukas Kovalik 12:11PMav mardVasil Vasilev ® 1:23 PMкато имаш време, разгледай този интересен ПР. https://github.com/jiminny/app/pull/12130Message Vasil Vasilev Lunch time...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84371
|
2906
|
21
|
2026-05-28T11:38:43.889248+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968323889_m2.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 2 new items - S Vasil Vasilev (DM) - Jiminny Inc - 2 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
platform-backend-engineers
platform-inner-team
ai-chapter
alerts
backend...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":6,"bounds":{"left":0.5056516,"top":0.058260176,"width":0.011968086,"height":0.028731046},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":6,"bounds":{"left":0.50299203,"top":0.10055866,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":8,"bounds":{"left":0.50664896,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":6,"bounds":{"left":0.50299203,"top":0.15482841,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":8,"bounds":{"left":0.50764626,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":6,"bounds":{"left":0.50299203,"top":0.20909816,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":8,"bounds":{"left":0.5053192,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5053192,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.50764626,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":6,"bounds":{"left":0.50299203,"top":0.26336792,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":8,"bounds":{"left":0.50797874,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.50797874,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.5099734,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":6,"bounds":{"left":0.50299203,"top":0.31763768,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":8,"bounds":{"left":0.50731385,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.50731385,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.5093085,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":6,"bounds":{"left":0.50299203,"top":0.3719074,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":8,"bounds":{"left":0.50731385,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.50731385,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.5106383,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-backend-engineers","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":15,"bounds":{"left":0.5422208,"top":0.096568234,"width":0.018284574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.5422208,"top":0.096568234,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.54521275,"top":0.096568234,"width":0.015292553,"height":0.014365523}}],"role_description":"text"}]...
|
7026011518978766690
|
-5794772930918924545
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
platform-backend-engineers
platform-inner-team
ai-chapter
alerts
backend
SluCkcolVIChRotonWindowHelp= github.com/jiminny/app/pull/12130v Gooc e Gemini© Pipelines - |IminnylappGemini 3.1 Pro ~* (JY-20613) Allow owner's role to txUewredtines on New codJY-20963 fix deleted object impsm.cwdSycaotionslsmalldcthatteM Inbox (1,733) - lukas.kovalik@jiminoonye Rosd ve php 81.15 dedPlatform Sorint 5.02 - Platform Te8 Jiminny7 (SRD-6881] (On demand) TransSona Strbramaal an at 27/05/2021O Illyana Netsova at 27/05/2026, 18Jy 20910 schedule parallel up: XRedis::set(SlockKey, true);kedws..expirelslockkey, setrt:loek_ffL-seconds);The Issue & Explanation:This PR extracts the metric logging into a new ReindexTargetStatsReporter class. Because thissystem now uses a multi-process worker model (thanks to the new Supervisor), multiple childprocesses can hit this block at the exact same microsecond.Process A and Process B both call Redis: :get (SlockKey) . Both receive null . Both then proceedto call Redis:: set (...) and push duplicate memory and queue size metrics to Datadog. Thisdefeats the purpose of the lock.The Fix: Use a single atomic Redis command. Redis: : set (SlockKey, true, 'EX',self::LOCK_TTL_SECONDS,"NX") will only set the key if it doesn't exist, returning false ifanother process beat it to the punch.4. Corrupted Stop Signal State on Exception (Logic Flaw)File Introduced in PR: app/Component/ES/EntityTypeReindexer.phpThe toroPHPSstopSignal-markSafeToStop(false);ShasWork = Sthis->updateProcessManager->doUpdateEntitiesChunk();SstopSignal->markSafeToStop(true);Improved GracefullyStoppable trait to correctly print exit message after 10seconds.Renortine Datadoa metrics is moved to a senarate class to keen concerns ofUpdateProcessManager more strict.Tests are updated accordingly.Added startup and exit logs.ano aso snor exo anaton<> Codejiminny / app &17 Pull requests 34G. AgeHomeDMsActivityLaterMoreYour lim nou chate trhn" uend to imnroy our moddle Camioiie 4l1t cao mata mtake co donbls chack " Yoir oracy & CaminSummarize pageJiminnY …simackend# bugs# confusion-clinic# donut_time# engineering# general# happy_birthday8 infosec.intemal.all# infra-changes# infrastructure de# jbu-team-info# jiminny-bg# platform-team# platform-tickets# product, launches# random# releases# support# thank-yous# the people_of jimi.…^ Direct messagesGo Vasil Vasilev •Stoyan TomovQ. lliyana Netseva8?. Petko Kashinski(D. Galya Dimitrova Eff. Stefka Stoyanova. Todor StamatovR. Steliyan Georgiev8. Ves(R. MiraPP. Nikolay Yankov4. James Graham2. Lukas Kovalik, ....#: Apps68 Jira Cloud• Toast@ Google Cale...Inu cowoy 14:50.4Q Describe what you are looking for€. Vasil Vasilev •e MessagerNoR0d canvis© Filesне знам дали го ползваш, но е много полезен туулUCoNyMayyuVasil Vasilev Ol 9:18 AMДобро утро, Лукашкогато имаш днес възможностмоля те поглелни тоя ПРhttps://github.com/jiminny/app/pull/12082Yasi Washley 1029 AMonaronhosTodaykas Kovallk tessздрасти Васко, може ли един approve https://github.com/jiminny/app/pull/12136Vasil Vasilev ©! 12:00 PMЗдрасти, Лукашготов сималко по косно и на мен ще ми тояова осню зи слин голям тенкuгьно ще ти пиша, като с готов за гледане (edited)Lukas Kovalik 12:11PMav mardVasil Vasilev ® 1:23 PMкато имаш време, разгледай този интересен ПР. https://github.com/jiminny/app/pull/121301.25 написах supervisor клас AsyncUpdateSupervisor, който се пали от supervisorcti, като тоя клас AsyncUpdateSupervisor пуска два паралелни процеса, един заобработка на активита и втори за обработка на сделкипропеснте сотлелнивеяненсетмоетаМяСТВолисльннена ВеЛИнни САто прОтесна можем лятим меним поотлелно косколко памеляле мсьответноонаслAсома пAaмеn н RCeки haICh no Tиrміли не си поечат, косато има ланни за инлескиоане в олашките и за астиїшу и за оорог иліMessage Vasil Vasilev Lunch time...
|
84368
|
NULL
|
NULL
|
NULL
|
|
84370
|
2905
|
26
|
2026-05-28T11:38:43.786296+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968323786_m1.jpg...
|
Slack
|
Vasil Vasilev (DM) - Jiminny Inc - 2 new items - S Vasil Vasilev (DM) - Jiminny Inc - 2 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
platform-backend-engineers
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
donut_time
engineering
general
happy_birthday
infosec_internal_all
infra-changes
infrastructure_dev
jbu-team-info
jiminny-bg
platform-team
platform-tickets
product_launches
random
releases
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Stoyan Tomov
Iliyana Netseva
Petko Kashinski
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Steliyan Georgiev
Ves
Mira
Nikolay Yankov
James Graham
Lukas Kovalik
you
Jira Cloud
Toast
Google Calendar
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Vasil Vasilev
May 18th at 10:17:38 AM
10:17 AM
Лукаш, привет
(edited)
May 18th at 10:17:59 AM
10:17
трябват ми няколко ревюта за разни ЕС промени
May 18th at 10:18:09 AM
10:18
разделени са на относително малки части
May 18th at 10:18:09 AM
10:18
https://github.com/jiminny/app/pull/12086
https://github.com/jiminny/app/pull/12086
May 18th at 10:18:17 AM
10:18
https://github.com/jiminny/app/pull/12088/changes
https://github.com/jiminny/app/pull/12088/changes
Vasil Vasilev...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":6,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":6,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":8,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":6,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":8,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":6,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":8,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":6,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":8,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":6,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":8,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":6,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":8,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":13,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-backend-engineers","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"donut_time","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"infosec_internal_all","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"infra-changes","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"infrastructure_dev","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jbu-team-info","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-team","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Iliyana Netseva","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mira","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Google Calendar","depth":15,"bounds":{"left":0.56805557,"top":0.0,"width":0.06388889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.56805557,"top":0.0,"width":0.007638889,"height":0.02}},{"char_start":1,"char_count":14,"bounds":{"left":0.57569444,"top":0.0,"width":0.06875,"height":0.02}}],"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":9,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":11,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":10,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":12,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":9,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":11,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Pins","depth":9,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Pins","depth":11,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":9,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":9,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":9,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":9,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":15,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":15,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:17:38 AM","depth":15,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:17 AM","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, привет","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:17:59 AM","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:17","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"трябват ми няколко ревюта за разни ЕС промени","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:18:09 AM","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:18","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"разделени са на относително малки части","depth":16,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:18:09 AM","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:18","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12086","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12086","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"May 18th at 10:18:17 AM","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:18","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/app/pull/12088/changes","depth":16,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/app/pull/12088/changes","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Vasil Vasilev","depth":15,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4763961715859228289
|
-1283576000832947026
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
platform-backend-engineers
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
donut_time
engineering
general
happy_birthday
infosec_internal_all
infra-changes
infrastructure_dev
jbu-team-info
jiminny-bg
platform-team
platform-tickets
product_launches
random
releases
support
thank-yous
the_people_of_jiminny
Vasil Vasilev
Stoyan Tomov
Iliyana Netseva
Petko Kashinski
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Steliyan Georgiev
Ves
Mira
Nikolay Yankov
James Graham
Lukas Kovalik
you
Jira Cloud
Toast
Google Calendar
Messages
Messages
Add canvas
Add canvas
Files
Files
Pins
Pins
Add and Edit Channel Tabs
Canvas
List
Folder
Vasil Vasilev
May 18th at 10:17:38 AM
10:17 AM
Лукаш, привет
(edited)
May 18th at 10:17:59 AM
10:17
трябват ми няколко ревюта за разни ЕС промени
May 18th at 10:18:09 AM
10:18
разделени са на относително малки части
May 18th at 10:18:09 AM
10:18
https://github.com/jiminny/app/pull/12086
https://github.com/jiminny/app/pull/12086
May 18th at 10:18:17 AM
10:18
https://github.com/jiminny/app/pull/12088/changes
https://github.com/jiminny/app/pull/12088/changes
Vasil Vasilev
SlackFile Edit→ViewGolHistoryWindowHelpllol100% C28 • Thu 28 May 14:38:43meet.google.com/axk-zwsm-vok?authuser=lukas.kovalik%40jiminny.comLukas Kovalik2:38 PM | Lukas/Stefka 121• 8:29...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
84369
|
2905
|
25
|
2026-05-28T11:38:40.887570+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968320887_m1.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response
Bad response
Share & export
Copy
Show more options
You said find potential issues
You said
find potential issues
Copy prompt
Gemini said
Gemini said
Based on the provided git diff of
UpdateProcessManagerTest.php
, here are the potential issues, risks, and improvements identified in the changes:
1. Missing setUpdateTarget Expectation in testEmptySelectionLogsAndReturnsFalse
1. Missing
setUpdateTarget
Expectation in
testEmptySelectionLogsAndReturnsFalse
In the newly added test
testEmptySelectionLogsAndReturnsFalse
, you explicitly mock the
BatchStatusManager
and set an expectation for
setUpdateTarget
:
PHP
Download code
Copy code
$batchStatusManager
->expects(
$this
->once())->method(
'setUpdateTarget'
)->with(
self
::UPDATE_TARGET);
However, later in the same test, you instantiate
UpdateProcessManager...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageEmitsGaugeWhenLockIsAbsent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageSkipsGaugeWhenLockIsPresent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely, as the Redis lock and Datadog gauge logic were removed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Empty Selection Test:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to verify that processing an empty selection logs a debug message, skips batch manager operations (","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), skips the stats reporter, and cleanly returns","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated Existing Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Modified","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunUpdate","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunDoUpdateButThrottled","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to assert that the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter->report()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method is called and to utilize the updated status manager mock.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Helper Method Refactoring","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Helper Method Refactoring","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Status Manager Assertions:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareStatusManager(int $invokeTimes = 0)","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to accept an integer. This allows tests to dynamically assert exactly how many times methods like","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are invoked.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Obsolete Helpers:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"prepareLogger()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"silenceDatadogAndRedisLock()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"helper methods, replacing their inline functionality with standard","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Log::shouldReceive","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expectations where needed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":15,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":15,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said find potential issues","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"find potential issues","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Based on the provided git diff of","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", here are the potential issues, risks, and improvements identified in the changes:","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Missing setUpdateTarget Expectation in testEmptySelectionLogsAndReturnsFalse","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Missing","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expectation in","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In the newly added test","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", you explicitly mock the","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BatchStatusManager","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and set an expectation for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setUpdateTarget","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PHP","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Download code","depth":18,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy code","depth":18,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"$batchStatusManager","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->expects(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->once())->method(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'setUpdateTarget'","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")->with(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"self","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"::UPDATE_TARGET);","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However, later in the same test, you instantiate","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
5383211682779405014
|
-3114347894345797500
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock.
Helper Method Refactoring
Helper Method Refactoring
Dynamic Status Manager Assertions:
Updated the
prepareStatusManager(int $invokeTimes = 0)
method to accept an integer. This allows tests to dynamically assert exactly how many times methods like
generateName
,
setUpdateTarget
,
scheduleWork
, and
finishWork
are invoked.
Removed Obsolete Helpers:
Deleted the
prepareLogger()
and
silenceDatadogAndRedisLock()
helper methods, replacing their inline functionality with standard
Log::shouldReceive
expectations where needed.
Good response
Bad response
Share & export
Copy
Show more options
You said find potential issues
You said
find potential issues
Copy prompt
Gemini said
Gemini said
Based on the provided git diff of
UpdateProcessManagerTest.php
, here are the potential issues, risks, and improvements identified in the changes:
1. Missing setUpdateTarget Expectation in testEmptySelectionLogsAndReturnsFalse
1. Missing
setUpdateTarget
Expectation in
testEmptySelectionLogsAndReturnsFalse
In the newly added test
testEmptySelectionLogsAndReturnsFalse
, you explicitly mock the
BatchStatusManager
and set an expectation for
setUpdateTarget
:
PHP
Download code
Copy code
$batchStatusManager
->expects(
$this
->once())->method(
'setUpdateTarget'
)->with(
self
::UPDATE_TARGET);
However, later in the same test, you instantiate
UpdateProcessManager...
|
84367
|
NULL
|
NULL
|
NULL
|
|
84368
|
2906
|
20
|
2026-05-28T11:38:38.771417+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-28/1779 /Users/lukas/.screenpipe/data/data/2026-05-28/1779968318771_m2.jpg...
|
Firefox
|
Jy 20910 schedule parallel update target processin Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12130
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock....
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.038065158,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.039893616,"top":0.0518755,"width":0.037898935,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"BE upgrade libraries","depth":4,"bounds":{"left":0.0028257978,"top":0.13288109,"width":0.03939495,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":4,"bounds":{"left":0.0,"top":0.15203512,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20613] Allow owner's role to be selected when setting up a trial - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.1632083,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Text relay","depth":4,"bounds":{"left":0.0028257978,"top":0.18994413,"width":0.020279255,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Deleted object error","depth":4,"bounds":{"left":0.0028257978,"top":0.21428572,"width":0.039228722,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.0028257978,"top":0.23782921,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uncovered Lines on New Code - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.015957447,"top":0.2490024,"width":0.11402926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.27055067,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.28172386,"width":0.14245346,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login | Salesforce","depth":4,"bounds":{"left":0.0,"top":0.30327216,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login | Salesforce","depth":5,"bounds":{"left":0.013297873,"top":0.31444532,"width":0.030917553,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":4,"bounds":{"left":0.0,"top":0.33599362,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app","depth":5,"bounds":{"left":0.013297873,"top":0.3471668,"width":0.24301861,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":4,"bounds":{"left":0.0,"top":0.36871508,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox (1,733) - lukas.kovalik@jiminny.com - Jiminny Mail","depth":5,"bounds":{"left":0.013297873,"top":0.37988827,"width":0.09740692,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":4,"bounds":{"left":0.0,"top":0.40143654,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20979] Resolve PHP 8.5.5 deprications - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.41260973,"width":0.08543883,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.43415803,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.44533122,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.4668795,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.47805268,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"transcript ss issue","depth":4,"bounds":{"left":0.0028257978,"top":0.5047885,"width":0.036070477,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.528332,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.5395052,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.56105345,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6881] [On demand] Transcription in saved search disappears - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.57222664,"width":0.1271609,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.5937749,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.6049481,"width":0.12799202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":4,"bounds":{"left":0.0028257978,"top":0.62649643,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket","depth":5,"bounds":{"left":0.015957447,"top":0.63766956,"width":0.12134308,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.6592179,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.6703911,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.69193935,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.70311254,"width":0.18201463,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.69912213,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.72625697,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":3,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":3,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Main menu","depth":5,"bounds":{"left":0.08228058,"top":0.09736632,"width":0.015957447,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open mode picker, currently 3.1 Pro","depth":6,"bounds":{"left":0.09823803,"top":0.10694334,"width":0.047539894,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":13,"bounds":{"left":0.1022274,"top":0.10853951,"width":0.017121011,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.1 Pro","depth":11,"bounds":{"left":0.12084442,"top":0.10853951,"width":0.013796543,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":5,"bounds":{"left":0.35854387,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":5,"bounds":{"left":0.37051198,"top":0.10215483,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":7,"bounds":{"left":0.079288565,"top":0.14445332,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":8,"bounds":{"left":0.079288565,"top":0.14684756,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\\Unit\\Component\\ES;5namespace Tests\\Unit\\Component\\ES;667-use ChaseConey\\LaravelDatadogHelper\\Datadog;8use Elastica\\Index;7use Elastica\\Index;9use Illuminate\\Support\\Facades\\App;8use Illuminate\\Support\\Facades\\App;10use Illuminate\\Support\\Facades\\Log;9use Illuminate\\Support\\Facades\\Log;@@ -20,6 +19,7 @@20use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;19use Jiminny\\Component\\ES\\Processor\\TargetEntitiesSelector;21use Jiminny\\Component\\ES\\Processor\\UpdateTarget;20use Jiminny\\Component\\ES\\Processor\\UpdateTarget;22use Jiminny\\Component\\ES\\QueuePriorityEnum;21use Jiminny\\Component\\ES\\QueuePriorityEnum;22+use Jiminny\\Component\\ES\\ReindexTargetStatsReporter;23use Jiminny\\Component\\ES\\UpdateProcessManager;23use Jiminny\\Component\\ES\\UpdateProcessManager;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;24use Jiminny\\Contracts\\ES\\UpdateTargetEnum;25use PHPUnit\\Framework\\Attributes\\CoversClass;25use PHPUnit\\Framework\\Attributes\\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \\Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a summary of the changes in the provided git diff for","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManagerTest.php","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Structural and Dependency Changes","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Structural and Dependency Changes","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Datadog:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ChaseConey\\LaravelDatadogHelper\\Datadog","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dependency and replaced it with","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\ES\\ReindexTargetStatsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Constants and Properties:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced a new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant (set to","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'testing'","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and a","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"property to hold the mock for the new stats reporter.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor Instantiation:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getProcessor()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method to inject the new","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mock into the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UpdateProcessManager","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and utilize the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ENVIRONMENT","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Test Case Modifications","depth":15,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Test Case Modifications","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Memory Logging Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deleted","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageEmitsGaugeWhenLockIsAbsent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testLogMemoryUsageSkipsGaugeWhenLockIsPresent","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely, as the Redis lock and Datadog gauge logic were removed.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added Empty Selection Test:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduced","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testEmptySelectionLogsAndReturnsFalse","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to verify that processing an empty selection logs a debug message, skips batch manager operations (","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"generateName","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"scheduleWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"finishWork","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), skips the stats reporter, and cleanly returns","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated Existing Tests:","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Modified","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunUpdate","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testRunDoUpdateButThrottled","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to assert that the","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$statsReporter->report()","depth":19,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method is called and to utilize the updated status manager mock.","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
3281297375678486283
|
-8014792054506229628
|
click
|
accessibility
|
NULL
|
Platform Sprint 5 Q2 - Platform Team - Scrum Board Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Pipelines - jiminny/app
Pipelines - jiminny/app
BE upgrade libraries
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
[JY-20613] Allow owner's role to be selected when setting up a trial - Jira
Text relay
Deleted object error
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
Uncovered Lines on New Code - app in Jiminny SonarQube Cloud
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
JY-20963 fix deleted object import by LakyLak · Pull Request #12121 · jiminny/app
Login | Salesforce
Login | Salesforce
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Jiminny\Exceptions\EmailActivityImportException: [Email Import] Failed for InboxEmail ID: 125695762: Error: Request failed — jiminny — app
Inbox (1,733) - [EMAIL] - Jiminny Mail
Inbox (1,733) - [EMAIL] - Jiminny Mail
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
[JY-20979] Resolve PHP 8.5.5 deprications - Jira
Jiminny
Jiminny
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 5 Q2 - Platform Team - Scrum Board - Jira
transcript ss issue
Jiminny
Jiminny
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
[SRD-6881] [On demand] Transcription in saved search disappears - Jira
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Sona Subramanian at 27/05/2026, 17:46:08 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Iliyana Netseva at 27/05/2026, 18:48:18 - Session Replay - LogRocket
Jiminny
Jiminny
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Jy 20910 schedule parallel update target processing by Vasil-Jiminny · Pull Request #12130 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
Main menu
Open mode picker, currently 3.1 Pro
Gemini
3.1 Pro
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
You said I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20910 schedule parallel update target processin</tabTitle>” with “<selection>@@ -4,7 +4,6 @@445namespace Tests\Unit\Component\ES;5namespace Tests\Unit\Component\ES;667-use ChaseConey\LaravelDatadogHelper\Datadog;8use Elastica\Index;7use Elastica\Index;9use Illuminate\Support\Facades\App;8use Illuminate\Support\Facades\App;10use Illuminate\Support\Facades\Log;9use Illuminate\Support\Facades\Log;@@ -20,6 +19,7 @@20use Jiminny\Component\ES\Processor\TargetEntitiesSelector;19use Jiminny\Component\ES\Processor\TargetEntitiesSelector;21use Jiminny\Component\ES\Processor\UpdateTarget;20use Jiminny\Component\ES\Processor\UpdateTarget;22use Jiminny\Component\ES\QueuePriorityEnum;21use Jiminny\Component\ES\QueuePriorityEnum;22+use Jiminny\Component\ES\ReindexTargetStatsReporter;23use Jiminny\Component\ES\UpdateProcessManager;23use Jiminny\Component\ES\UpdateProcessManager;24use Jiminny\Contracts\ES\UpdateTargetEnum;24use Jiminny\Contracts\ES\UpdateTargetEnum;25use PHPUnit\Framework\Attributes\CoversClass;25use PHPUnit\Framework\Attributes\CoversClass;@@ -31,6 +31,7 @@ class UpdateProcessManagerTest extends TestCase31{31{32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';32private const string BATCH_NAME = '9440de7a-1c0f-4541-a235-592f2117bb20';33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;33private const string UPDATE_TARGET = UpdateTarget::ACTIVITY;34+private const string ENVIRONMENT = 'testing';343535private array $normalPriority = [];36private array $normalPriority = [];36private array $highPriority = [];37private array $highPriority = [];@@ -40,6 +41,7 @@ class UpdateProcessManagerTest extends TestCase40private ?SimpleCollection $documentsToUpdate = null;41private ?SimpleCollection $documentsToUpdate = null;414242private BatchStatusManager|MockObject|null $batchStatusManager = null;43private BatchStatusManager|MockObject|null $batchStatusManager = null;44+private ReindexTargetStatsReporter|MockObject|null $statsReporter = null;43private Index|MockObject|null $targetIndex = null;45private Index|MockObject|null $targetIndex = null;444645private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;47private string|UpdateTargetEnum $updateTargetEntity = UpdateTarget::ACTIVITY;@@ -68,8 +70,13 @@ protected function setUp(): void68array_diff($allEntities, $deleteIds)70array_diff($allEntities, $deleteIds)69 );71 );707271-$this->prepareStatusManager();73+$this->statsReporter = $this->createMock(ReindexTargetStatsReporter::class);72-$this->prepareLogger();74+$this->statsReporter->expects($this->once())75+ ->method('setEnvironment')76+ ->with(self::ENVIRONMENT);77+$this->statsReporter->expects($this->once())78+ ->method('setUpdateTarget')79+ ->with(self::UPDATE_TARGET);73 }80 }748175/**82/**@@ -81,76 +88,75 @@ public function testRunUpdate(): void81// Also test that the trait works with entities and strings alike88// Also test that the trait works with entities and strings alike82$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;89$this->updateTargetEntity = UpdateTargetEnum::ACTIVITY;839084-$this->silenceDatadogAndRedisLock();91+ Log::shouldReceive('info')->withAnyArgs();92+ Log::shouldReceive('debug')->withAnyArgs();93+94+$this->statsReporter->expects($this->once())->method('report');95+96+$this->prepareStatusManager(1);859786$processor = $this->getProcessor();98$processor = $this->getProcessor();879988// There are exactly 250 chunks100// There are exactly 250 chunks89$this->assertTrue($processor->doUpdateEntitiesChunk());101$this->assertTrue($processor->doUpdateEntitiesChunk());102+90// But the second execution is on empty set103// But the second execution is on empty set91$this->assertFalse($processor->doUpdateEntitiesChunk());104$this->assertFalse($processor->doUpdateEntitiesChunk());92 }105 }9310694-/**107+public function testEmptySelectionLogsAndReturnsFalse(): void95- * When no Redis lock exists, logMemoryUsage should set the lock and emit a Datadog gauge96- * with the correct stat name, sample rate, and environment/type tags.97- */98-public function testLogMemoryUsageEmitsGaugeWhenLockIsAbsent(): void99 {108 {100-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);109+$batchStatusManager = $this->createMock(BatchStatusManager::class);101-110+$batchStatusManager->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);102- Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(null);111+$batchStatusManager->expects($this->never())->method('generateName');103- Redis::shouldReceive('set')->once()->with($gaugeLockKey, true);112+$batchStatusManager->expects($this->never())->method('scheduleWork');104- Redis::shouldReceive('expire')->once()->with($gaugeLockKey, 60);113+$batchStatusManager->expects($this->never())->method('finishWork');105-106- Datadog::shouldReceive('increment')->once()->withAnyArgs();107- Datadog::shouldReceive('gauge')108- ->once()109- ->with(110-'jiminny.reindex-memory-usage',111- \Mockery::type('int'),112-1,113- ['environment' => 'staging', 'type' => self::UPDATE_TARGET]114- );115-116-$processor = $this->getProcessor();117-$processor->setEnvironment('staging');118114119-$processor->doUpdateEntitiesChunk();115+$emptySelection = $this->createMock(SelectionList::class);120-}116+ $emptySelection->expects($this->once())->method('isEmpty')->willReturn(true);121117122-/**118+$entitySelector = $this->createMock(TargetEntitiesSelector::class);123- * When a Redis lock already exists, logMemoryUsage should return early119+$entitySelector->expects($this->once())->method('setUpdateTarget')->with(self::UPDATE_TARGET);124- * and not emit a Datadog gauge.120+$entitySelector->expects($this->once())->method('setBatchStatusManager')->with($batchStatusManager);125- */121+$entitySelector->expects($this->once())->method('select')->willReturn($emptySelection);126-public function testLogMemoryUsageSkipsGaugeWhenLockIsPresent(): void127- {128-$gaugeLockKey = sprintf('%s-process-manager-lock', self::UPDATE_TARGET);129122130-Redis::shouldReceive('get')->once()->with($gaugeLockKey)->andReturn(true);123+Log::shouldReceive('debug')131-Redis::shouldReceive('set')->never();124+ ->once()132-Redis::shouldReceive('expire')->never();125+ ->with('[ EsUpdateProcessManager ] Empty selection', ['update_target' => self::UPDATE_TARGET]);133126134- Datadog::shouldReceive('increment')->once()->withAnyArgs();127+$this->statsReporter->expects($this->never())->method('report');135- Datadog::shouldReceive('gauge')->never();136128137-$processor = $this->getProcessor();129+$processor = new UpdateProcessManager(138-$processor->setEnvironment('staging');130+ esClient: $this->getEsClientMock(),131+ entitySelector: $entitySelector,132+ batchStatusManager: $batchStatusManager,133+ deleteDocumentsAction: $this->createMock(DeleteDocumentsAction::class),134+ upsertDocumentsAction: $this->createMock(UpsertDocumentsAction::class),135+ loadDocumentsAction: $this->createMock(LoadDocumentsAction::class),136+ statsReporter: $this->statsReporter,137+ );138+$processor->setEnvironment(self::ENVIRONMENT);139+$processor->setUpdateTarget(self::UPDATE_TARGET);140+$processor->bootstrap();139141140-$processor->doUpdateEntitiesChunk();142+$this->assertFalse($processor->doUpdateEntitiesChunk());141 }143 }142144143public function testRunDoUpdateButThrottled(): void145public function testRunDoUpdateButThrottled(): void144 {146 {145$this->isThrottled = true;147$this->isThrottled = true;146148147-$this->silenceDatadogAndRedisLock();149+ Log::shouldReceive('info')->withAnyArgs();150+151+$this->statsReporter->expects($this->once())->method('report');148152149// Reschedule High priority153// Reschedule High priority150 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);154 Redis::shouldReceive('saddarray')->with('activities-for-update-priority', $this->highPriority);151// Reschedule low priority155// Reschedule low priority152 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);156 Redis::shouldReceive('saddarray')->with('activities-for-update', $this->normalPriority);153157158+$this->prepareStatusManager(1);159+154$processor = $this->getProcessor();160$processor = $this->getProcessor();155161156$this->assertTrue($processor->doUpdateEntitiesChunk());162$this->assertTrue($processor->doUpdateEntitiesChunk());@@ -165,10 +171,11 @@ private function getProcessor(): UpdateProcessManager165 deleteDocumentsAction: $this->getDeleteActionMock(),171 deleteDocumentsAction: $this->getDeleteActionMock(),166 upsertDocumentsAction: $this->getUpsertActionMock(),172 upsertDocumentsAction: $this->getUpsertActionMock(),167 loadDocumentsAction: $this->getLoadDocumentsMock(),173 loadDocumentsAction: $this->getLoadDocumentsMock(),174+ statsReporter: $this->statsReporter,168 );175 );169176170$updateProcessor->setUpdateTarget($this->updateTargetEntity);177$updateProcessor->setUpdateTarget($this->updateTargetEntity);171-$updateProcessor->setEnvironment('test-env');178+$updateProcessor->setEnvironment(self::ENVIRONMENT);172179173$updateProcessor->bootstrap();180$updateProcessor->bootstrap();174181@@ -195,23 +202,6 @@ private function getEsClientMock(): Client|MockObject195return $clientMock;202return $clientMock;196 }203 }197204198-private function prepareLogger(): void199- {200- Log::shouldReceive('info')201- ->atLeast()202- ->once()203- ->with('[ EsUpdateProcessManager ] Finished updating entities in ES', $this->anything());204- }205-206-private function silenceDatadogAndRedisLock(): void207- {208- Datadog::shouldReceive('increment')->atLeast()->once()->withAnyArgs();209- Datadog::shouldReceive('gauge')->withAnyArgs();210- Redis::shouldReceive('get')->withAnyArgs()->andReturn(null);211- Redis::shouldReceive('set')->withAnyArgs();212- Redis::shouldReceive('expire')->withAnyArgs();213- }214-215private function getDeleteActionMock(): DeleteDocumentsAction|MockObject205private function getDeleteActionMock(): DeleteDocumentsAction|MockObject216 {206 {217$deleteAction = $this->createMock(DeleteDocumentsAction::class);207$deleteAction = $this->createMock(DeleteDocumentsAction::class);@@ -320,26 +310,30 @@ private function mockSelection(): SelectionList|MockObject320return $selectionList;310return $selectionList;321 }311 }322312323-private function prepareStatusManager(): void313+private function prepareStatusManager(int $invokeTimes = 0): void324 {314 {325$batchStatusManager = $this->createMock(BatchStatusManager::class);315$batchStatusManager = $this->createMock(BatchStatusManager::class);326316327-$batchStatusManager->expects($this->atLeastOnce())317+if ($invokeTimes) {318+$batchStatusManager->expects($this->once())319+ ->method('setUpdateTarget')320+ ->with(self::UPDATE_TARGET);321+ } else {322+$batchStatusManager->expects($this->never())->method('setUpdateTarget');323+ }324+325+$batchStatusManager->expects($this->exactly($invokeTimes))328 ->method('generateName')326 ->method('generateName')329 ->willReturn(self::BATCH_NAME);327 ->willReturn(self::BATCH_NAME);330328331-$batchStatusManager->expects($this->atLeastOnce())329+$batchStatusManager->expects($this->exactly($invokeTimes))332- ->method('setUpdateTarget')333- ->with(self::UPDATE_TARGET);334-335-$batchStatusManager->expects($this->atLeastOnce())336 ->method('scheduleWork')330 ->method('scheduleWork')337 ->with(331 ->with(338array_merge($this->highPriority, $this->normalPriority),332array_merge($this->highPriority, $this->normalPriority),339self::BATCH_NAME333self::BATCH_NAME340 );334 );341335342-$batchStatusManager->expects($this->atLeastOnce())336+$batchStatusManager->expects($this->exactly($invokeTimes))343 ->method('finishWork')337 ->method('finishWork')344 ->with(self::BATCH_NAME);338 ->with(self::BATCH_NAME);345339</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Copy prompt
Gemini said
Gemini said
Here is a summary of the changes in the provided git diff for
UpdateProcessManagerTest.php
:
Structural and Dependency Changes
Structural and Dependency Changes
Replaced Datadog:
Removed the
ChaseConey\LaravelDatadogHelper\Datadog
dependency and replaced it with
Jiminny\Component\ES\ReindexTargetStatsReporter
.
Added Constants and Properties:
Introduced a new
ENVIRONMENT
constant (set to
'testing'
) and a
$statsReporter
property to hold the mock for the new stats reporter.
Processor Instantiation:
Updated the
getProcessor()
method to inject the new
$statsReporter
mock into the
UpdateProcessManager
and utilize the
ENVIRONMENT
constant.
Test Case Modifications
Test Case Modifications
Removed Memory Logging Tests:
Deleted
testLogMemoryUsageEmitsGaugeWhenLockIsAbsent
and
testLogMemoryUsageSkipsGaugeWhenLockIsPresent
entirely, as the Redis lock and Datadog gauge logic were removed.
Added Empty Selection Test:
Introduced
testEmptySelectionLogsAndReturnsFalse
to verify that processing an empty selection logs a debug message, skips batch manager operations (
generateName
,
scheduleWork
,
finishWork
), skips the stats reporter, and cleanly returns
false
.
Updated Existing Tests:
Modified
testRunUpdate
and
testRunDoUpdateButThrottled
to assert that the
$statsReporter->report()
method is called and to utilize the updated status manager mock....
|
NULL
|
NULL
|
NULL
|
NULL
|