Skip to content

Conversation

litetex
Copy link
Member

@litetex litetex commented Jul 11, 2025

Based on/Required before merging:

List of fixes:

Made all tests mockable

Fixes #1276

  • You can now unplug your internet cable, run the tests with -Ddownloader=MOCK and everything will work
  • Tests in mock mode run in <5s in the IDE
  • Migrated data structure accordingly
  • Various minor improvements to downloader caching system
    • Added REC alias for RECORDING downloader (so that I have to type less)
  • Tests that do network communication MUST implement InitNewPipeTest (or InitYoutubeTest for YT) so that the downloader is setup correctly
  • Added a few classes for abstraction like DefaultSimpleExtractorTest and DefaultSimpleUntypedExtractorTest
    • This removes a TON (multiple hundred/thousand lines) of boilerplate code
  • Fixed: Some tests setup the downloader but never used it (particular LinkHandler-Tests)
  • Removed a bunch of region comments that are not region comments

YT

  • Fix Never Gonna Give You Up video having a different title (YoutubeMixPlaylistExtractorTest)
  • Disabled YoutubeMusicSearchExtractorTest - "showing results for ..." doesn't seem to be returned by the backend anymore, however the code is still present in the JS frontend.
    • Added caching for YoutubeMusicSearchExtractor to not do the same work multiple times
  • Fix YoutubeStreamExtractorRelatedMixTest randomly failing:
    Mix Videos can also display non-mix playlists in the related items:
  • Regenerated all YT mocks

Soundcloud

  • Top 50 list no longer exists (not present at https://soundcloud.com/charts) → Removed
  • User for SoundcloudChannelTabExtractorTest#Playlists no longer exists → Replaced with another user
    • Chose a relatively big user that (also) makes copyright free music to ensure maximum test reliability
  • Fetch Charts in onFetchPage and not always when getInitialPage is called

Also:
Fixes #1283


@litetex litetex changed the title Fix all tests / Update mocks Fix all tests and make everything work offline Jul 12, 2025
@litetex litetex marked this pull request as ready for review July 12, 2025 13:12
@litetex litetex changed the title Fix all tests and make everything work offline Fix all tests and make everything work offline/with mocks Jul 12, 2025
@TobiGr TobiGr added soundcloud service, https://soundcloud.com/ youtube service, https://www.youtube.com/ codequality Improvements to the codebase to improve the code quality tests Issues and PR related to unit tests labels Jul 12, 2025
@TobiGr
Copy link
Contributor

TobiGr commented Jul 13, 2025

Thank you. I was really needed to get more reliable tests and better detect flaws in PRs.

Top 50 list no longer exists (not present at https://soundcloud.com/charts) → Removed

Isn't it just called All music genres now? The thumbnails explicitly says TOP 50. All other charts are TOP 50 for a specific genre.

Copy link
Contributor

@TobiGr TobiGr left a comment

Choose a reason for hiding this comment

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

As already noted, these are relly good changes. I did not review SoundcloudChartsExtractor, but everything else related to the test changes which should be done by somebody else with more recent knowledge about the SoundCloud structure.

@litetex
Copy link
Member Author

litetex commented Jul 13, 2025

Top 50 list no longer exists (not present at https://soundcloud.com/charts) → Removed

Isn't it just called All music genres now? The thumbnails explicitly says TOP 50. All other charts are TOP 50 for a specific genre.

Oh I didn't notice that.

Update: Nope, that's not the Top 50 anymore they seems to have completely reworked how charts work.

There is also no more https://soundcloud.com/charts/top or https://soundcloud.com/charts/new just https://soundcloud.com/charts which then has links to various sets (aka playlists).

https://api-v2.soundcloud.com/charts?genre=soundcloud:genres:all-music&client_id=MoLbAg35TuqjYwWVtNIKyRPFScQGMOBY&kind=top (used for Top 50) returns nothing while the variant with kind=trending (for New & hot) still works

@TobiGr
Copy link
Contributor

TobiGr commented Jul 13, 2025

Update: Nope, that's not the Top 50 anymore they seems to have completely reworked how charts work.

Thanks for taking a closer look and sorry for causing confusion :)

@litetex
Copy link
Member Author

litetex commented Jul 14, 2025

Update: Nope, that's not the Top 50 anymore they seems to have completely reworked how charts work.

Thanks for taking a closer look and sorry for causing confusion :)

No problem :)
I created a new issue to track this: #1335

Forgotten comment

Rebased, should be gone now ^^

@Stypox Stypox force-pushed the fix-all-tests branch 2 times, most recently from 8f2c322 to 1be3bc7 Compare July 16, 2025 15:02
Copy link
Member

@Stypox Stypox left a comment

Choose a reason for hiding this comment

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

Thank you! The commits are a bit messy but I guess there was no way to organize them better, given the huge amount of changes. I reviewed everything now and it seems ok. If any of my comments do not apply to the latest code, please ignore them, I could only review commits instead of the whole code as the browser would start lagging 😅

  • 4277341 is only updating mocks, and that somehow fixed the test?
  • There are actually various SoundCloud trending categories here, though it's out-of-scope for this PR to implement them.

@litetex
Copy link
Member Author

litetex commented Jul 16, 2025

4277341 is only updating mocks, and that somehow fixed the test?

I'm not quite sure what happend there but I somehow got corrupted mocks, it didn't happen in subsequent runs so I think it might have been some sort of very weird race condition or YT just didn't like me xD

There are actually various SoundCloud trending categories here, though it's out-of-scope for this PR to implement them.

Belongs to #1335 ;)

@litetex
Copy link
Member Author

litetex commented Jul 16, 2025

@Stypox
Ty for the detailed review.

A few tests are currently failing due to the rebase I will have a look at them and after that (when the CI is green) we can probably merge/SQUASH if there is nothing else

Update: 2197 test passed, 108 ignored - We are good to go

litetex and others added 13 commits July 16, 2025 19:52
From review:
* Fix format
* Use ``extractorUrl`` name
* YoutubeStreamLinkHandlerFactoryTest setup with no downloader

Co-Authored-By: Tobi <[email protected]>
They no longer exists and the API returns nothing for them.

Overall SoundCloud seems to use a new system.
Co-Authored-By: Stypox <[email protected]>
Co-Authored-By: Stypox <[email protected]>
Co-Authored-By: Stypox <[email protected]>
Co-Authored-By: Stypox <[email protected]>
Co-Authored-By: Stypox <[email protected]>
Co-Authored-By: Stypox <[email protected]>
litetex added 2 commits July 16, 2025 20:20
These are currently not working, but the tests said OK because it was not checked what happens if the returned parameter is empty!

-> TeamNewPipe#1339
@litetex
Copy link
Member Author

litetex commented Jul 16, 2025

There is currently a problem with n-Parameter deobfuscation, which is not working at all.
I created #1339 to handle this and disabled the test for now.

public void setUp() throws Exception {
super.setUp();

extractor(); // Initialize
Copy link
Member

Choose a reason for hiding this comment

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

What I meant here is to put extractor() directly in super.setUp() so we don't have to ever worry about the extractor not being initialized, or would that create issues? There are various other places where I saw // Init comments

Copy link
Member Author

@litetex litetex Jul 17, 2025

Choose a reason for hiding this comment

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

What I meant here is to put extractor() directly in super.setUp() so we don't have to ever worry about the extractor not being initialized, or would that create issues?

Yes because there is no setUp method that creates an extractor when the class derives from InitYoutubeTest.

Also regarding "so we don't have to ever worry about the extractor not being initialized" there is a reason why this is lazily initialized:
We had a bunch of tests where there was a extractor used exactly in this way but it was never used.
When initializing the extractor during setup all tests mark it as used despite maybe never doing so.

There are various other places where I saw // Init comments

These are all places where this is used:
grafik

I now also refactored both classes to use dedicated methods which initialize the extractor.

@TobiGr
Copy link
Contributor

TobiGr commented Jul 18, 2025

This requires app changes / a migration when Top 50 kiosk is set as main page. Otherwise, you'll get this crash when starting the app:

Stacktrace
FATAL EXCEPTION: main
Process: org.schabi.newpipe.debug, PID: 7205
java.lang.NullPointerException: Attempt to read from field 'org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory org.schabi.newpipe.extractor.kiosk.KioskList$KioskEntry.handlerFactory' on a null object reference in method 'org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory org.schabi.newpipe.extractor.kiosk.KioskList.getListLinkHandlerFactoryByType(java.lang.String)'
	at org.schabi.newpipe.extractor.kiosk.KioskList.getListLinkHandlerFactoryByType(KioskList.java:146)
	at org.schabi.newpipe.fragments.list.kiosk.KioskFragment.getInstance(KioskFragment.java:81)
	at org.schabi.newpipe.settings.tabs.Tab$KioskTab.getFragment(Tab.java:357)
	at org.schabi.newpipe.settings.tabs.Tab$KioskTab.getFragment(Tab.java:313)
	at org.schabi.newpipe.fragments.MainFragment$SelectedTabsPagerAdapter.getItem(MainFragment.java:305)
	at androidx.fragment.app.FragmentStatePagerAdapterMenuWorkaround.instantiateItem(FragmentStatePagerAdapterMenuWorkaround.java:169)
	at androidx.viewpager.widget.ViewPager.addNewItem(ViewPager.java:1010)
	at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1158)
	at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1092)
	at androidx.viewpager.widget.ViewPager.onMeasure(ViewPager.java:1622)
	at android.view.View.measure(View.java:26496)
	at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:735)
	at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:481)
	at android.view.View.measure(View.java:26496)
	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
	at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
	at android.view.View.measure(View.java:26496)
	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
	at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:760)
	at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:833)
	at android.view.View.measure(View.java:26496)
	at androidx.drawerlayout.widget.DrawerLayout.onMeasure(DrawerLayout.java:1156)
	at android.view.View.measure(View.java:26496)
	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
	at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
	at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:145)
	at android.view.View.measure(View.java:26496)
	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
	at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1608)
	at android.widget.LinearLayout.measureVertical(LinearLayout.java:878)
	at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
	at android.view.View.measure(View.java:26496)
	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
	at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
	at android.view.View.measure(View.java:26496)
	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
	at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1608)
	at android.widget.LinearLayout.measureVertical(LinearLayout.java:878)
	at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
	at android.view.View.measure(View.java:26496)
	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
	at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
	at com.android.internal.policy.DecorView.onMeasure(DecorView.java:760)
	at android.view.View.measure(View.java:26496)
	at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:4042)
	at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:2658)
	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2964)
	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2371)
	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9297)
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1231)
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
	at android.view.Choreographer.doCallbacks(Choreographer.java:899)
	at android.view.Choreographer.doFrame(Choreographer.java:832)
	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
	at android.os.Handler.handleCallback(Handler.java:942)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at android.os.Looper.loopOnce(Looper.java:201)
	at android.os.Looper.loop(Looper.java:288)
	at android.app.ActivityThread.main(ActivityThread.java:7924)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

@TobiGr TobiGr merged commit 404f503 into TeamNewPipe:dev Jul 18, 2025
4 checks passed
TobiGr pushed a commit to TobiGr/NewPipeExtractor that referenced this pull request Jul 18, 2025
Fix all tests and make everything work offline/with mocks.
Remove old mocks and generate new ones with new structure.

Remove SoundCloud "Top 50" kiosk.
@litetex litetex deleted the fix-all-tests branch July 18, 2025 20:38
@TobiGr TobiGr mentioned this pull request Jul 21, 2025
3 tasks
whistlingwoods pushed a commit to whistlingwoods/NewPipeExtractor that referenced this pull request Aug 13, 2025
Fix all tests and make everything work offline/with mocks.
Remove old mocks and generate new ones with new structure.

Remove SoundCloud "Top 50" kiosk.
@Stypox
Copy link
Member

Stypox commented Oct 4, 2025

Note: SoundCloud's clientId is stored statically and thus fetched only in one test. However, if that test is not executed again before all others, the clientId will not be set and other tests will try to obtain it with a call to https://soundcloud.com, but will fail because they have no mock request for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codequality Improvements to the codebase to improve the code quality soundcloud service, https://soundcloud.com/ tests Issues and PR related to unit tests youtube service, https://www.youtube.com/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failed build in gradle NewPipe Extractor Mock downloader for everything

3 participants