package fbmessenger_test import ( "context" "io" "testing" "github.com/apex/log" engine "github.com/ooni/probe-cli/v3/internal/engine" "github.com/ooni/probe-cli/v3/internal/engine/experiment/fbmessenger" "github.com/ooni/probe-cli/v3/internal/engine/experiment/urlgetter" "github.com/ooni/probe-cli/v3/internal/engine/mockable" "github.com/ooni/probe-cli/v3/internal/engine/netx/tracex" "github.com/ooni/probe-cli/v3/internal/model" "github.com/ooni/probe-cli/v3/internal/netxlite" ) func TestNewExperimentMeasurer(t *testing.T) { measurer := fbmessenger.NewExperimentMeasurer(fbmessenger.Config{}) if measurer.ExperimentName() != "facebook_messenger" { t.Fatal("unexpected name") } if measurer.ExperimentVersion() != "0.2.0" { t.Fatal("unexpected version") } } func TestSuccess(t *testing.T) { if testing.Short() { t.Skip("skip test in short mode") } measurer := fbmessenger.NewExperimentMeasurer(fbmessenger.Config{}) ctx := context.Background() // we need a real session because we need the ASN database sess := newsession(t) measurement := new(model.Measurement) callbacks := model.NewPrinterCallbacks(log.Log) err := measurer.Run(ctx, sess, measurement, callbacks) if err != nil { t.Fatal(err) } tk := measurement.TestKeys.(*fbmessenger.TestKeys) if *tk.FacebookBAPIDNSConsistent != true { t.Fatal("invalid FacebookBAPIDNSConsistent") } if *tk.FacebookBAPIReachable != true { t.Fatal("invalid FacebookBAPIReachable") } if *tk.FacebookBGraphDNSConsistent != true { t.Fatal("invalid FacebookBGraphDNSConsistent") } if *tk.FacebookBGraphReachable != true { t.Fatal("invalid FacebookBGraphReachable") } if *tk.FacebookEdgeDNSConsistent != true { t.Fatal("invalid FacebookEdgeDNSConsistent") } if *tk.FacebookEdgeReachable != true { t.Fatal("invalid FacebookEdgeReachable") } if *tk.FacebookExternalCDNDNSConsistent != true { t.Fatal("invalid FacebookExternalCDNDNSConsistent") } if *tk.FacebookExternalCDNReachable != true { t.Fatal("invalid FacebookExternalCDNReachable") } if *tk.FacebookScontentCDNDNSConsistent != true { t.Fatal("invalid FacebookScontentCDNDNSConsistent") } if *tk.FacebookScontentCDNReachable != true { t.Fatal("invalid FacebookScontentCDNReachable") } if *tk.FacebookStarDNSConsistent != true { t.Fatal("invalid FacebookStarDNSConsistent") } if *tk.FacebookStarReachable != true { t.Fatal("invalid FacebookStarReachable") } if *tk.FacebookSTUNDNSConsistent != true { t.Fatal("invalid FacebookSTUNDNSConsistent") } if tk.FacebookSTUNReachable != nil { t.Fatal("invalid FacebookSTUNReachable") } if *tk.FacebookDNSBlocking != false { t.Fatal("invalid FacebookDNSBlocking") } if *tk.FacebookTCPBlocking != false { t.Fatal("invalid FacebookTCPBlocking") } } func TestWithCancelledContext(t *testing.T) { measurer := fbmessenger.NewExperimentMeasurer(fbmessenger.Config{}) ctx, cancel := context.WithCancel(context.Background()) cancel() // so we fail immediately sess := &mockable.Session{MockableLogger: log.Log} measurement := new(model.Measurement) callbacks := model.NewPrinterCallbacks(log.Log) err := measurer.Run(ctx, sess, measurement, callbacks) if err != nil { t.Fatal(err) } tk := measurement.TestKeys.(*fbmessenger.TestKeys) if *tk.FacebookBAPIDNSConsistent != false { t.Fatal("invalid FacebookBAPIDNSConsistent") } if tk.FacebookBAPIReachable != nil { t.Fatal("invalid FacebookBAPIReachable") } if *tk.FacebookBGraphDNSConsistent != false { t.Fatal("invalid FacebookBGraphDNSConsistent") } if tk.FacebookBGraphReachable != nil { t.Fatal("invalid FacebookBGraphReachable") } if *tk.FacebookEdgeDNSConsistent != false { t.Fatal("invalid FacebookEdgeDNSConsistent") } if tk.FacebookEdgeReachable != nil { t.Fatal("invalid FacebookEdgeReachable") } if *tk.FacebookExternalCDNDNSConsistent != false { t.Fatal("invalid FacebookExternalCDNDNSConsistent") } if tk.FacebookExternalCDNReachable != nil { t.Fatal("invalid FacebookExternalCDNReachable") } if *tk.FacebookScontentCDNDNSConsistent != false { t.Fatal("invalid FacebookScontentCDNDNSConsistent") } if tk.FacebookScontentCDNReachable != nil { t.Fatal("invalid FacebookScontentCDNReachable") } if *tk.FacebookStarDNSConsistent != false { t.Fatal("invalid FacebookStarDNSConsistent") } if tk.FacebookStarReachable != nil { t.Fatal("invalid FacebookStarReachable") } if *tk.FacebookSTUNDNSConsistent != false { t.Fatal("invalid FacebookSTUNDNSConsistent") } if tk.FacebookSTUNReachable != nil { t.Fatal("invalid FacebookSTUNReachable") } if *tk.FacebookDNSBlocking != true { t.Fatal("invalid FacebookDNSBlocking") } // no TCP blocking because we didn't ever reach TCP connect if *tk.FacebookTCPBlocking != false { t.Fatal("invalid FacebookTCPBlocking") } sk, err := measurer.GetSummaryKeys(measurement) if err != nil { t.Fatal(err) } if _, ok := sk.(fbmessenger.SummaryKeys); !ok { t.Fatal("invalid type for summary keys") } } func TestComputeEndpointStatsTCPBlocking(t *testing.T) { failure := io.EOF.Error() operation := netxlite.ConnectOperation tk := fbmessenger.TestKeys{} tk.Update(urlgetter.MultiOutput{ Input: urlgetter.MultiInput{Target: fbmessenger.ServiceEdge}, TestKeys: urlgetter.TestKeys{ Failure: &failure, FailedOperation: &operation, Queries: []tracex.DNSQueryEntry{{ Answers: []tracex.DNSAnswerEntry{{ ASN: fbmessenger.FacebookASN, }}, }}, }, }) if *tk.FacebookEdgeDNSConsistent != true { t.Fatal("invalid FacebookEdgeDNSConsistent") } if *tk.FacebookEdgeReachable != false { t.Fatal("invalid FacebookEdgeReachable") } if tk.FacebookDNSBlocking != nil { // meaning: not determined yet t.Fatal("invalid FacebookDNSBlocking") } if *tk.FacebookTCPBlocking != true { t.Fatal("invalid FacebookTCPBlocking") } } func TestComputeEndpointStatsDNSIsLying(t *testing.T) { failure := io.EOF.Error() operation := netxlite.ConnectOperation tk := fbmessenger.TestKeys{} tk.Update(urlgetter.MultiOutput{ Input: urlgetter.MultiInput{Target: fbmessenger.ServiceEdge}, TestKeys: urlgetter.TestKeys{ Failure: &failure, FailedOperation: &operation, Queries: []tracex.DNSQueryEntry{{ Answers: []tracex.DNSAnswerEntry{{ ASN: 0, }}, }}, }, }) if *tk.FacebookEdgeDNSConsistent != false { t.Fatal("invalid FacebookEdgeDNSConsistent") } if tk.FacebookEdgeReachable != nil { t.Fatal("invalid FacebookEdgeReachable") } if *tk.FacebookDNSBlocking != true { t.Fatal("invalid FacebookDNSBlocking") } if tk.FacebookTCPBlocking != nil { // meaning: not determined yet t.Fatal("invalid FacebookTCPBlocking") } } func newsession(t *testing.T) model.ExperimentSession { sess, err := engine.NewSession(context.Background(), engine.SessionConfig{ AvailableProbeServices: []model.OOAPIService{{ Address: "https://ams-pg-test.ooni.org", Type: "https", }}, Logger: log.Log, SoftwareName: "ooniprobe-engine", SoftwareVersion: "0.0.1", }) if err != nil { t.Fatal(err) } if err := sess.MaybeLookupLocation(); err != nil { t.Fatal(err) } return sess } func TestSummaryKeysInvalidType(t *testing.T) { measurement := new(model.Measurement) m := &fbmessenger.Measurer{} _, err := m.GetSummaryKeys(measurement) if err.Error() != "invalid test keys type" { t.Fatal("not the error we expected") } } func TestSummaryKeysWithNils(t *testing.T) { measurement := &model.Measurement{TestKeys: &fbmessenger.TestKeys{}} m := &fbmessenger.Measurer{} osk, err := m.GetSummaryKeys(measurement) if err != nil { t.Fatal(err) } sk := osk.(fbmessenger.SummaryKeys) if sk.DNSBlocking { t.Fatal("invalid dnsBlocking") } if sk.TCPBlocking { t.Fatal("invalid tcpBlocking") } if sk.IsAnomaly { t.Fatal("invalid isAnomaly") } } func TestSummaryKeysWithFalseFalse(t *testing.T) { falsy := false measurement := &model.Measurement{TestKeys: &fbmessenger.TestKeys{ FacebookTCPBlocking: &falsy, FacebookDNSBlocking: &falsy, }} m := &fbmessenger.Measurer{} osk, err := m.GetSummaryKeys(measurement) if err != nil { t.Fatal(err) } sk := osk.(fbmessenger.SummaryKeys) if sk.DNSBlocking { t.Fatal("invalid dnsBlocking") } if sk.TCPBlocking { t.Fatal("invalid tcpBlocking") } if sk.IsAnomaly { t.Fatal("invalid isAnomaly") } } func TestSummaryKeysWithFalseTrue(t *testing.T) { falsy := false truy := true measurement := &model.Measurement{TestKeys: &fbmessenger.TestKeys{ FacebookTCPBlocking: &falsy, FacebookDNSBlocking: &truy, }} m := &fbmessenger.Measurer{} osk, err := m.GetSummaryKeys(measurement) if err != nil { t.Fatal(err) } sk := osk.(fbmessenger.SummaryKeys) if sk.DNSBlocking == false { t.Fatal("invalid dnsBlocking") } if sk.TCPBlocking { t.Fatal("invalid tcpBlocking") } if sk.IsAnomaly == false { t.Fatal("invalid isAnomaly") } } func TestSummaryKeysWithTrueFalse(t *testing.T) { falsy := false truy := true measurement := &model.Measurement{TestKeys: &fbmessenger.TestKeys{ FacebookTCPBlocking: &truy, FacebookDNSBlocking: &falsy, }} m := &fbmessenger.Measurer{} osk, err := m.GetSummaryKeys(measurement) if err != nil { t.Fatal(err) } sk := osk.(fbmessenger.SummaryKeys) if sk.DNSBlocking { t.Fatal("invalid dnsBlocking") } if sk.TCPBlocking == false { t.Fatal("invalid tcpBlocking") } if sk.IsAnomaly == false { t.Fatal("invalid isAnomaly") } } func TestSummaryKeysWithTrueTrue(t *testing.T) { truy := true measurement := &model.Measurement{TestKeys: &fbmessenger.TestKeys{ FacebookTCPBlocking: &truy, FacebookDNSBlocking: &truy, }} m := &fbmessenger.Measurer{} osk, err := m.GetSummaryKeys(measurement) if err != nil { t.Fatal(err) } sk := osk.(fbmessenger.SummaryKeys) if sk.DNSBlocking == false { t.Fatal("invalid dnsBlocking") } if sk.TCPBlocking == false { t.Fatal("invalid tcpBlocking") } if sk.IsAnomaly == false { t.Fatal("invalid isAnomaly") } }