Skip to content

Commit 349ba8d

Browse files
litetexAudricV
authored andcommitted
Improve tests and randomness
- Use the existing RNG inside YoutubeParsingHelper - Deduplicated test-setup for YouTube tests - Minor improvements
1 parent 5237694 commit 349ba8d

21 files changed

Lines changed: 251 additions & 342 deletions

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java

Lines changed: 38 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
/*
2+
* Created by Christian Schabesberger on 02.03.16.
3+
*
4+
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
5+
* YoutubeParsingHelper.java is part of NewPipe Extractor.
6+
*
7+
* NewPipe Extractor is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* NewPipe Extractor is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with NewPipe Extractor. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
121
package org.schabi.newpipe.extractor.services.youtube;
222

323
import static org.schabi.newpipe.extractor.NewPipe.getDownloader;
@@ -7,7 +27,6 @@
727
import static org.schabi.newpipe.extractor.utils.Utils.UTF_8;
828
import static org.schabi.newpipe.extractor.utils.Utils.getStringResultFromRegexArray;
929
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
10-
import static org.schabi.newpipe.extractor.utils.Utils.randomStringFromAlphabet;
1130

1231
import com.grack.nanojson.JsonArray;
1332
import com.grack.nanojson.JsonBuilder;
@@ -29,6 +48,7 @@
2948
import org.schabi.newpipe.extractor.stream.Description;
3049
import org.schabi.newpipe.extractor.utils.JsonUtils;
3150
import org.schabi.newpipe.extractor.utils.Parser;
51+
import org.schabi.newpipe.extractor.utils.RandomStringFromAlphabetGenerator;
3252
import org.schabi.newpipe.extractor.utils.Utils;
3353

3454
import java.io.IOException;
@@ -37,6 +57,7 @@
3757
import java.net.URL;
3858
import java.net.URLDecoder;
3959
import java.nio.charset.StandardCharsets;
60+
import java.security.SecureRandom;
4061
import java.time.LocalDate;
4162
import java.time.OffsetDateTime;
4263
import java.time.ZoneOffset;
@@ -54,26 +75,6 @@
5475
import javax.annotation.Nonnull;
5576
import javax.annotation.Nullable;
5677

57-
/*
58-
* Created by Christian Schabesberger on 02.03.16.
59-
*
60-
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
61-
* YoutubeParsingHelper.java is part of NewPipe Extractor.
62-
*
63-
* NewPipe Extractor is free software: you can redistribute it and/or modify
64-
* it under the terms of the GNU General Public License as published by
65-
* the Free Software Foundation, either version 3 of the License, or
66-
* (at your option) any later version.
67-
*
68-
* NewPipe Extractor is distributed in the hope that it will be useful,
69-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
70-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
71-
* GNU General Public License for more details.
72-
*
73-
* You should have received a copy of the GNU General Public License
74-
* along with NewPipe Extractor. If not, see <https://www.gnu.org/licenses/>.
75-
*/
76-
7778
public final class YoutubeParsingHelper {
7879

7980
private YoutubeParsingHelper() {
@@ -83,11 +84,6 @@ private YoutubeParsingHelper() {
8384
public static final String CPN = "cpn";
8485
public static final String VIDEO_ID = "videoId";
8586

86-
/**
87-
* Seed that will be used for video tests, in order to mock video requests.
88-
*/
89-
private static final long SEED_FOR_VIDEOS_TESTS = 3000;
90-
9187
private static final String HARDCODED_CLIENT_VERSION = "2.20220114.01.00";
9288
private static final String HARDCODED_KEY = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8";
9389

@@ -122,7 +118,7 @@ private YoutubeParsingHelper() {
122118
private static final String CONTENT_PLAYBACK_NONCE_ALPHABET =
123119
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
124120

125-
private static Random numberGenerator = new Random();
121+
private static Random numberGenerator = new SecureRandom();
126122

127123
/**
128124
* {@code PENDING+} means that the user did not yet submit their choices.
@@ -606,12 +602,13 @@ public static String getClientVersion() throws IOException, ExtractionException
606602

607603
if (keyAndVersionExtracted) {
608604
return clientVersion;
609-
} else {
610-
if (areHardcodedClientVersionAndKeyValid()) {
611-
clientVersion = HARDCODED_CLIENT_VERSION;
612-
return clientVersion;
613-
}
614605
}
606+
607+
if (areHardcodedClientVersionAndKeyValid()) {
608+
clientVersion = HARDCODED_CLIENT_VERSION;
609+
return clientVersion;
610+
}
611+
615612
throw new ExtractionException("Could not get YouTube WEB client version");
616613
}
617614

@@ -631,11 +628,11 @@ public static String getKey() throws IOException, ExtractionException {
631628

632629
if (keyAndVersionExtracted) {
633630
return key;
634-
} else {
635-
if (areHardcodedClientVersionAndKeyValid()) {
636-
key = HARDCODED_KEY;
637-
return key;
638-
}
631+
}
632+
633+
if (areHardcodedClientVersionAndKeyValid()) {
634+
key = HARDCODED_KEY;
635+
return key;
639636
}
640637

641638
// The ANDROID API key is also valid with the WEB client so return it if we couldn't
@@ -1508,7 +1505,8 @@ public static String unescapeDocument(@Nonnull final String doc) {
15081505
*/
15091506
@Nonnull
15101507
public static String generateContentPlaybackNonce() {
1511-
return randomStringFromAlphabet(CONTENT_PLAYBACK_NONCE_ALPHABET, 16);
1508+
return RandomStringFromAlphabetGenerator.generate(
1509+
CONTENT_PLAYBACK_NONCE_ALPHABET, 16, numberGenerator);
15121510
}
15131511

15141512
/**
@@ -1524,23 +1522,7 @@ public static String generateContentPlaybackNonce() {
15241522
*/
15251523
@Nonnull
15261524
public static String generateTParameter() {
1527-
return randomStringFromAlphabet(CONTENT_PLAYBACK_NONCE_ALPHABET, 12);
1528-
}
1529-
1530-
/**
1531-
* Set the seed for video tests.
1532-
*
1533-
* <p>
1534-
* This seed will be used to generate the same {@code t} and {@code cpn} values between
1535-
* different execution of tests so mocks can be used for stream tests.
1536-
* </p>
1537-
*
1538-
* <p>
1539-
* This method will call {@link Utils#setSecureRandomSeed(long)} with the
1540-
* {@link #SEED_FOR_VIDEOS_TESTS value}.
1541-
* </p>
1542-
*/
1543-
public static void setSeedForVideoTests() {
1544-
Utils.setSecureRandomSeed(SEED_FOR_VIDEOS_TESTS);
1525+
return RandomStringFromAlphabetGenerator.generate(
1526+
CONTENT_PLAYBACK_NONCE_ALPHABET, 12, numberGenerator);
15451527
}
15461528
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.schabi.newpipe.extractor.utils;
2+
3+
import java.util.Random;
4+
5+
import javax.annotation.Nonnull;
6+
7+
/**
8+
* Generates a random string from a predefined alphabet.
9+
*/
10+
public final class RandomStringFromAlphabetGenerator {
11+
private RandomStringFromAlphabetGenerator() {
12+
// No impl
13+
}
14+
15+
/**
16+
* Generate a random string from an alphabet.
17+
*
18+
* @param alphabet the characters' alphabet to use
19+
* @param length the length of the returned string (> 0)
20+
* @param random {@link Random} (or better {@link java.security.SecureRandom}) used for generating the random string
21+
* @return a random string of the requested length made of only characters from the provided
22+
* alphabet
23+
*/
24+
@Nonnull
25+
public static String generate(
26+
final String alphabet,
27+
final int length,
28+
final Random random) {
29+
final StringBuilder stringBuilder = new StringBuilder(length);
30+
for (int i = 0; i < length; i++) {
31+
stringBuilder.append(alphabet.charAt(random.nextInt(alphabet.length())));
32+
}
33+
return stringBuilder.toString();
34+
}
35+
}

extractor/src/main/java/org/schabi/newpipe/extractor/utils/Utils.java

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88
import java.net.MalformedURLException;
99
import java.net.URL;
1010
import java.net.URLDecoder;
11+
import java.util.ArrayList;
1112
import java.util.Arrays;
1213
import java.util.Collection;
1314
import java.util.Iterator;
1415
import java.util.LinkedList;
15-
import java.util.ArrayList;
1616
import java.util.List;
1717
import java.util.Map;
18-
import java.security.SecureRandom;
1918
import java.util.regex.Pattern;
2019

2120
public final class Utils {
@@ -26,7 +25,6 @@ public final class Utils {
2625
public static final String EMPTY_STRING = "";
2726
private static final Pattern M_PATTERN = Pattern.compile("(https?)?:\\/\\/m\\.");
2827
private static final Pattern WWW_PATTERN = Pattern.compile("(https?)?:\\/\\/www\\.");
29-
private static final SecureRandom random = new SecureRandom();
3028

3129
private Utils() {
3230
// no instance
@@ -75,8 +73,9 @@ public static long mixedNumberWordToLong(final String numberWord)
7573
multiplier = Parser.matchGroup("[\\d]+([\\.,][\\d]+)?([KMBkmb])+", numberWord, 2);
7674
} catch (final ParsingException ignored) {
7775
}
78-
final double count = Double.parseDouble(
79-
Parser.matchGroup1("([\\d]+([\\.,][\\d]+)?)", numberWord).replace(",", "."));
76+
77+
final double count = Double.parseDouble(Parser.matchGroup1("([\\d]+([\\.,][\\d]+)?)",
78+
numberWord).replace(",", "."));
8079
switch (multiplier.toUpperCase()) {
8180
case "K":
8281
return (long) (count * 1e3);
@@ -443,43 +442,4 @@ public static String getStringResultFromRegexArray(@Nonnull final String input,
443442
}
444443
return result;
445444
}
446-
447-
/**
448-
* Generate a random string using the secure random device {@link #random}.
449-
*
450-
* <p>
451-
* {@link #setSecureRandomSeed(long)} might be useful when mocking tests.
452-
* </p>
453-
*
454-
* @param alphabet the characters' alphabet to use
455-
* @param length the length of the returned string
456-
* @return a random string of the requested length made of only characters from the provided
457-
* alphabet
458-
*/
459-
@Nonnull
460-
public static String randomStringFromAlphabet(final String alphabet, final int length) {
461-
final StringBuilder stringBuilder = new StringBuilder();
462-
for (int i = 0; i < length; ++i) {
463-
stringBuilder.append(alphabet.charAt(random.nextInt(alphabet.length())));
464-
}
465-
return stringBuilder.toString();
466-
}
467-
468-
/**
469-
* Seed the secure random device used for {@link #randomStringFromAlphabet(String, int)}.
470-
*
471-
* <p>
472-
* Use this in tests so that they can be mocked as the same random numbers are always
473-
* generated.
474-
* </p>
475-
*
476-
* <p>
477-
* This is not intended to be used outside of tests.
478-
* </p>
479-
*
480-
* @param seed the seed to pass to {@link SecureRandom#setSeed(long)}
481-
*/
482-
public static void setSecureRandomSeed(final long seed) {
483-
random.setSeed(seed);
484-
}
485445
}

extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractorTest.java

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
package org.schabi.newpipe.extractor.services.youtube;
22

3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
import static org.junit.jupiter.api.Assertions.assertTrue;
7+
import static org.junit.jupiter.api.Assertions.fail;
8+
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertContains;
9+
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
10+
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
11+
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestGetPageInNewExtractor;
12+
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestMoreItems;
13+
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRelatedItems;
14+
315
import org.junit.jupiter.api.BeforeAll;
416
import org.junit.jupiter.api.Test;
517
import org.schabi.newpipe.downloader.DownloaderFactory;
@@ -15,13 +27,6 @@
1527
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeChannelExtractor;
1628

1729
import java.io.IOException;
18-
import java.util.Random;
19-
20-
import static org.junit.jupiter.api.Assertions.*;
21-
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertContains;
22-
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
23-
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
24-
import static org.schabi.newpipe.extractor.services.DefaultTests.*;
2530

2631
/**
2732
* Test for {@link ChannelExtractor}
@@ -33,8 +38,7 @@ public class YoutubeChannelExtractorTest {
3338
public static class NotAvailable {
3439
@BeforeAll
3540
public static void setUp() throws IOException {
36-
YoutubeParsingHelper.resetClientVersionAndKey();
37-
YoutubeParsingHelper.setNumberGenerator(new Random(1));
41+
YoutubeTestsUtils.ensureStateless();
3842
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "notAvailable"));
3943
}
4044

@@ -130,8 +134,7 @@ public void accountTerminatedCopyrightFetch() throws Exception {
130134
public static class NotSupported {
131135
@BeforeAll
132136
public static void setUp() throws IOException {
133-
YoutubeParsingHelper.resetClientVersionAndKey();
134-
YoutubeParsingHelper.setNumberGenerator(new Random(1));
137+
YoutubeTestsUtils.ensureStateless();
135138
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "notSupported"));
136139
}
137140

@@ -149,8 +152,7 @@ public static class Gronkh implements BaseChannelExtractorTest {
149152

150153
@BeforeAll
151154
public static void setUp() throws Exception {
152-
YoutubeParsingHelper.resetClientVersionAndKey();
153-
YoutubeParsingHelper.setNumberGenerator(new Random(1));
155+
YoutubeTestsUtils.ensureStateless();
154156
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "gronkh"));
155157
extractor = (YoutubeChannelExtractor) YouTube
156158
.getChannelExtractor("http://www.youtube.com/user/Gronkh");
@@ -246,8 +248,7 @@ public static class VSauce implements BaseChannelExtractorTest {
246248

247249
@BeforeAll
248250
public static void setUp() throws Exception {
249-
YoutubeParsingHelper.resetClientVersionAndKey();
250-
YoutubeParsingHelper.setNumberGenerator(new Random(1));
251+
YoutubeTestsUtils.ensureStateless();
251252
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "VSauce"));
252253
extractor = (YoutubeChannelExtractor) YouTube
253254
.getChannelExtractor("https://www.youtube.com/user/Vsauce");
@@ -342,8 +343,7 @@ public static class Kurzgesagt implements BaseChannelExtractorTest {
342343

343344
@BeforeAll
344345
public static void setUp() throws Exception {
345-
YoutubeParsingHelper.resetClientVersionAndKey();
346-
YoutubeParsingHelper.setNumberGenerator(new Random(1));
346+
YoutubeTestsUtils.ensureStateless();
347347
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "kurzgesagt"));
348348
extractor = (YoutubeChannelExtractor) YouTube
349349
.getChannelExtractor("https://www.youtube.com/channel/UCsXVk37bltHxD1rDPwtNM8Q");
@@ -460,8 +460,7 @@ public static class CaptainDisillusion implements BaseChannelExtractorTest {
460460

461461
@BeforeAll
462462
public static void setUp() throws Exception {
463-
YoutubeParsingHelper.resetClientVersionAndKey();
464-
YoutubeParsingHelper.setNumberGenerator(new Random(1));
463+
YoutubeTestsUtils.ensureStateless();
465464
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "captainDisillusion"));
466465
extractor = (YoutubeChannelExtractor) YouTube
467466
.getChannelExtractor("https://www.youtube.com/user/CaptainDisillusion/videos");
@@ -555,8 +554,7 @@ public static class RandomChannel implements BaseChannelExtractorTest {
555554

556555
@BeforeAll
557556
public static void setUp() throws Exception {
558-
YoutubeParsingHelper.resetClientVersionAndKey();
559-
YoutubeParsingHelper.setNumberGenerator(new Random(1));
557+
YoutubeTestsUtils.ensureStateless();
560558
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "random"));
561559
extractor = (YoutubeChannelExtractor) YouTube
562560
.getChannelExtractor("https://www.youtube.com/channel/UCUaQMQS9lY5lit3vurpXQ6w");

0 commit comments

Comments
 (0)