refactor: introduce and use InputOrStaticDefault (#632)

This commit introduces a new `InputLoader` policy by which, if no
input is provided, we use a static default input list.

We also modify the code to use this policy for dnscheck and
stunreachability, with proper input.

We also modify `miniooni` to pass the new `ExperimentName` field to
the `InputLoader` to indicate which default input list to use.

This diff is part of a set of diffs aiming at fixing
https://github.com/ooni/probe/issues/1814 and has been
extracted from https://github.com/ooni/probe-cli/pull/539.

What remains to be done, after this diff has landed is to ensure
things also work for ooniprobe and oonimkall.
This commit is contained in:
Simone Basso 2021-12-03 15:30:56 +01:00 committed by GitHub
commit 2044b78a5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 296 additions and 6 deletions

View file

@ -6,6 +6,7 @@ import (
"io"
"io/fs"
"os"
"strings"
"syscall"
"testing"
@ -206,6 +207,134 @@ func TestInputLoaderInputStrictlyRequiredWithEmptyFile(t *testing.T) {
}
}
func TestInputLoaderInputOrStaticDefaultWithInput(t *testing.T) {
il := &InputLoader{
ExperimentName: "dnscheck",
StaticInputs: []string{"https://www.google.com/"},
SourceFiles: []string{
"testdata/inputloader1.txt",
"testdata/inputloader2.txt",
},
InputPolicy: InputOrStaticDefault,
}
ctx := context.Background()
out, err := il.Load(ctx)
if err != nil {
t.Fatal(err)
}
if len(out) != 5 {
t.Fatal("not the output length we expected")
}
expect := []model.URLInfo{
{URL: "https://www.google.com/"},
{URL: "https://www.x.org/"},
{URL: "https://www.slashdot.org/"},
{URL: "https://abc.xyz/"},
{URL: "https://run.ooni.io/"},
}
if diff := cmp.Diff(out, expect); diff != "" {
t.Fatal(diff)
}
}
func TestInputLoaderInputOrStaticDefaultWithEmptyFile(t *testing.T) {
il := &InputLoader{
ExperimentName: "dnscheck",
InputPolicy: InputOrStaticDefault,
SourceFiles: []string{
"testdata/inputloader1.txt",
"testdata/inputloader3.txt", // we want it before inputloader2.txt
"testdata/inputloader2.txt",
},
}
ctx := context.Background()
out, err := il.Load(ctx)
if !errors.Is(err, ErrDetectedEmptyFile) {
t.Fatalf("not the error we expected: %+v", err)
}
if out != nil {
t.Fatal("not the output we expected")
}
}
func TestInputLoaderInputOrStaticDefaultWithoutInputDNSCheck(t *testing.T) {
il := &InputLoader{
ExperimentName: "dnscheck",
InputPolicy: InputOrStaticDefault,
}
ctx := context.Background()
out, err := il.Load(ctx)
if err != nil {
t.Fatal(err)
}
if len(out) != len(dnsCheckDefaultInput) {
t.Fatal("invalid output length")
}
for idx := 0; idx < len(dnsCheckDefaultInput); idx++ {
e := out[idx]
if e.CategoryCode != "MISC" {
t.Fatal("invalid category code")
}
if e.CountryCode != "XX" {
t.Fatal("invalid country code")
}
if e.URL != dnsCheckDefaultInput[idx] {
t.Fatal("invalid URL")
}
}
}
func TestInputLoaderInputOrStaticDefaultWithoutInputStunReachability(t *testing.T) {
il := &InputLoader{
ExperimentName: "stunreachability",
InputPolicy: InputOrStaticDefault,
}
ctx := context.Background()
out, err := il.Load(ctx)
if err != nil {
t.Fatal(err)
}
if len(out) != len(stunReachabilityDefaultInput) {
t.Fatal("invalid output length")
}
for idx := 0; idx < len(stunReachabilityDefaultInput); idx++ {
e := out[idx]
if e.CategoryCode != "MISC" {
t.Fatal("invalid category code")
}
if e.CountryCode != "XX" {
t.Fatal("invalid country code")
}
if e.URL != stunReachabilityDefaultInput[idx] {
t.Fatal("invalid URL")
}
}
}
func TestStaticBareInputForExperimentWorksWithNonCanonicalNames(t *testing.T) {
names := []string{"DNSCheck", "STUNReachability"}
for _, name := range names {
if _, err := staticInputForExperiment(name); err != nil {
t.Fatal("failure for", name, ":", err)
}
}
}
func TestInputLoaderInputOrStaticDefaultWithoutInputOtherName(t *testing.T) {
il := &InputLoader{
ExperimentName: "xx",
InputPolicy: InputOrStaticDefault,
}
ctx := context.Background()
out, err := il.Load(ctx)
if !errors.Is(err, ErrNoStaticInput) {
t.Fatal("not the error we expected", err)
}
if out != nil {
t.Fatal("expected nil result here")
}
}
func TestInputLoaderInputOrQueryBackendWithInput(t *testing.T) {
il := &InputLoader{
StaticInputs: []string{"https://www.google.com/"},
@ -494,3 +623,59 @@ func TestInputLoaderLoggerWorksAsIntended(t *testing.T) {
t.Fatal("logger not working as intended")
}
}
func TestStringListToModelURLInfoWithValidInput(t *testing.T) {
input := []string{
"stun://stun.voip.blackberry.com:3478",
"stun://stun.altar.com.pl:3478",
}
output, err := stringListToModelURLInfo(input, nil)
if err != nil {
t.Fatal(err)
}
if len(input) != len(output) {
t.Fatal("unexpected output length")
}
for idx := 0; idx < len(input); idx++ {
if input[idx] != output[idx].URL {
t.Fatal("unexpected entry")
}
if output[idx].CategoryCode != "MISC" {
t.Fatal("unexpected category")
}
if output[idx].CountryCode != "XX" {
t.Fatal("unexpected country")
}
}
}
func TestStringListToModelURLInfoWithInvalidInput(t *testing.T) {
input := []string{
"stun://stun.voip.blackberry.com:3478",
"\t", // <- not a valid URL
"stun://stun.altar.com.pl:3478",
}
output, err := stringListToModelURLInfo(input, nil)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("no the error we expected", err)
}
if output != nil {
t.Fatal("unexpected nil output")
}
}
func TestStringListToModelURLInfoWithError(t *testing.T) {
input := []string{
"stun://stun.voip.blackberry.com:3478",
"\t",
"stun://stun.altar.com.pl:3478",
}
expected := errors.New("mocked error")
output, err := stringListToModelURLInfo(input, expected)
if !errors.Is(err, expected) {
t.Fatal("no the error we expected", err)
}
if output != nil {
t.Fatal("unexpected nil output")
}
}