diff --git a/internal/experiment/webconnectivitylte/analysisclassic.go b/internal/experiment/webconnectivitylte/analysisclassic.go index daaa75c574..b2fcabf835 100644 --- a/internal/experiment/webconnectivitylte/analysisclassic.go +++ b/internal/experiment/webconnectivitylte/analysisclassic.go @@ -1,5 +1,12 @@ package webconnectivitylte +// +// The "classic" analysis engine. +// +// We try to emulate results produced by v0.4 of Web Connectivity and +// also attempt to provide a more fine-grained view of the results. +// + import ( "github.com/ooni/probe-cli/v3/internal/minipipeline" "github.com/ooni/probe-cli/v3/internal/model" @@ -8,7 +15,8 @@ import ( ) // AnalysisEngineClassic is an alternative analysis engine that aims to produce -// results that are backward compatible with Web Connectivity v0.4. +// results that are backward compatible with Web Connectivity v0.4 while also +// procuding more fine-grained blocking flags. func AnalysisEngineClassic(tk *TestKeys, logger model.Logger) { tk.analysisClassic(logger) } @@ -31,26 +39,29 @@ func (tk *TestKeys) analysisClassic(logger model.Logger) { runtimex.Try0(container.IngestControlMessages(tk.ControlRequest, tk.Control)) } - // 2. filter observations to only include results collected by the + // 2. compute extended analysis flags + analysisExtMain(tk, container) + + // 3. filter observations to only include results collected by the // system resolver, which approximates v0.4's results classic := minipipeline.ClassicFilter(container) // 3. produce a web observations analysis based on the web observations woa := minipipeline.AnalyzeWebObservationsWithLinearAnalysis(classic) - // 4. determine the DNS consistency + // 5. determine the DNS consistency tk.DNSConsistency = analysisClassicDNSConsistency(woa) - // 5. set DNSExperimentFailure + // 6. set DNSExperimentFailure if !woa.DNSExperimentFailure.IsNone() && woa.DNSExperimentFailure.Unwrap() != "" { value := woa.DNSExperimentFailure.Unwrap() tk.DNSExperimentFailure = &value } - // 6. compute the HTTPDiff values + // 7. compute the HTTPDiff values tk.setHTTPDiffValues(woa) - // 7. compute blocking & accessible + // 8. compute blocking & accessible analysisClassicComputeBlockingAccessible(woa, tk) } @@ -72,6 +83,7 @@ func analysisClassicDNSConsistency(woa *minipipeline.WebAnalysis) optional.Value } func (tk *TestKeys) setHTTPDiffValues(woa *minipipeline.WebAnalysis) { + // TODO(bassosimone): this code should use [newAnalysisHTTPDiffStatus]. const bodyProportionFactor = 0.7 if !woa.HTTPFinalResponseDiffBodyProportionFactor.IsNone() { tk.BodyProportion = woa.HTTPFinalResponseDiffBodyProportionFactor.Unwrap() @@ -116,6 +128,7 @@ var _ analysisClassicTestKeysProxy = &TestKeys{} // httpDiff implements analysisClassicTestKeysProxy. func (tk *TestKeys) httpDiff() bool { + // TODO(bassosimone): this code should use [newAnalysisHTTPDiffStatus]. if tk.StatusCodeMatch != nil && *tk.StatusCodeMatch { if tk.BodyLengthMatch != nil && *tk.BodyLengthMatch { return false diff --git a/internal/experiment/webconnectivitylte/analysisext.go b/internal/experiment/webconnectivitylte/analysisext.go new file mode 100644 index 0000000000..0a03c95202 --- /dev/null +++ b/internal/experiment/webconnectivitylte/analysisext.go @@ -0,0 +1,223 @@ +package webconnectivitylte + +// +// The extended ("ext") analysis sub-engine (used by "classic"). +// +// We analyze all the produced observations without limiting ourselves to +// analyzing observations rooted into getaddrinfo lookups. +// + +import ( + "fmt" + "io" + "strings" + + "github.com/ooni/probe-cli/v3/internal/minipipeline" +) + +// analysisExtMain computes the extended analysis. +// +// This function MUTATES the [*TestKeys]. +func analysisExtMain(tk *TestKeys, container *minipipeline.WebObservationsContainer) { + // compute the web analysis + analysis := minipipeline.AnalyzeWebObservationsWithoutLinearAnalysis(container) + + // prepare for emitting informational messages + var info strings.Builder + + // DNS & address analysis matching with control info (i.e., analysis + // of what happened during the 0th redirect) + analysisExtDNS(tk, analysis, &info) + + // endpoint (TCP, TLS, HTTP) failure analysis matching with control info (i.e., analysis + // of what happened during the 0th redirect) + analysisExtEndpointFailure(tk, analysis, &info) + + // error occurring during redirects (which we can possibly explain if the control + // succeeded in getting a webpage from the target server) + analysisExtRedirectErrors(tk, analysis, &info) + + // HTTP success analysis (i.e., only if we manage to get an HTTP response) + analysisExtHTTPFinalResponse(tk, analysis, &info) + + // TODO(bassosimone): we need to also compute the null-null flags here + + // print the content of the analysis only if there's some content to print + if content := info.String(); content != "" { + fmt.Printf("\n") + fmt.Printf("Extended Analysis\n") + fmt.Printf("-----------------\n") + fmt.Printf("%s", content) + fmt.Printf("\n\n") + } +} + +func analysisExtDNS(tk *TestKeys, analysis *minipipeline.WebAnalysis, info io.Writer) { + // note: here we want to match all the possible conditions because + // we're processing N >= 1 DNS lookups. + + if failures := analysis.DNSLookupSuccessWithBogonAddresses; failures.Len() > 0 { + tk.BlockingFlags |= AnalysisBlockingFlagDNSBlocking + tk.DNSFlags |= AnalysisFlagDNSBogon + fmt.Fprintf(info, "- transactions with bogon IP addrs: %s\n", failures.String()) + } + + if failures := analysis.DNSLookupUnexpectedFailure; failures.Len() > 0 { + tk.BlockingFlags |= AnalysisBlockingFlagDNSBlocking + tk.DNSFlags |= AnalysisDNSFlagUnexpectedFailure + fmt.Fprintf(info, "- transactions with unexpected DNS lookup failures: %s\n", failures.String()) + } + + if failures := analysis.DNSLookupSuccessWithInvalidAddresses; failures.Len() > 0 { + tk.BlockingFlags |= AnalysisBlockingFlagDNSBlocking + tk.DNSFlags |= AnalysisDNSFlagUnexpectedAddrs + fmt.Fprintf(info, "- transactions with invalid IP addrs: %s\n", failures.String()) + } +} + +func analysisExtEndpointFailure(tk *TestKeys, analysis *minipipeline.WebAnalysis, info io.Writer) { + // note: here we want to match all the possible conditions because + // we're processing N >= 1 endpoint measurements (with the exception + // of HTTP but it makes sense to also process HTTP failures here). + // + // also note that the definition of "unexpected" implies that we could + // use the TH to establish some expectations. + + // TCP analysis + if failures := analysis.TCPConnectUnexpectedFailure; failures.Len() > 0 { + tk.BlockingFlags |= AnalysisBlockingFlagTCPIPBlocking + fmt.Fprintf(info, "- transactions with unexpected TCP connect failures: %s\n", failures.String()) + } + + // TLS analysis + if failures := analysis.TLSHandshakeUnexpectedFailure; failures.Len() > 0 { + tk.BlockingFlags |= AnalysisBlockingFlagTLSBlocking + fmt.Fprintf(info, "- transactions with unexpected TLS handshake failures: %s\n", failures.String()) + } + + // HTTP failure analysis + if failures := analysis.HTTPRoundTripUnexpectedFailure; failures.Len() > 0 { + tk.BlockingFlags |= AnalysisBlockingFlagHTTPBlocking + fmt.Fprintf(info, "- transactions with unexpected HTTP round trip failures: %s\n", failures.String()) + } +} + +func analysisExtHTTPFinalResponse(tk *TestKeys, analysis *minipipeline.WebAnalysis, info io.Writer) { + // case #1: HTTP final response without control + // + // we don't know what to do in this case. + if success := analysis.HTTPFinalResponseSuccessTCPWithoutControl; !success.IsNone() { + fmt.Fprintf( + info, + "- there is no control information to compare to the final response (transaction: %d)\n", + success.Unwrap(), + ) + return + } + + // case #2: HTTPS final response without control + // + // this is automatic success. + if success := analysis.HTTPFinalResponseSuccessTLSWithoutControl; !success.IsNone() { + fmt.Fprintf(info, "- the final response (transaction: %d) uses TLS: automatic success\n", success.Unwrap()) + tk.BlockingFlags |= AnalysisBlockingFlagSuccess + return + } + + // case #3: HTTPS final response with control + // + // this is also automatic success. + if success := analysis.HTTPFinalResponseSuccessTLSWithControl; !success.IsNone() { + fmt.Fprintf(info, "- the final response (transaction: %d) uses TLS: automatic success\n", success.Unwrap()) + tk.BlockingFlags |= AnalysisBlockingFlagSuccess + return + } + + // case #4: HTTP final response with control + // + // we need to run HTTPDiff + if success := analysis.HTTPFinalResponseSuccessTCPWithControl; !success.IsNone() { + txID := success.Unwrap() + hds := newAnalysisHTTPDiffStatus(analysis) + if hds.httpDiff() { + tk.BlockingFlags |= AnalysisBlockingFlagHTTPDiff + fmt.Fprintf(info, "- the final response (transaction: %d) differs from the control response\n", txID) + return + } + fmt.Fprintf(info, "- the final response (transaction: %d) matches the control response\n", txID) + tk.BlockingFlags |= AnalysisBlockingFlagSuccess + return + } +} + +func analysisExtRedirectErrors(tk *TestKeys, analysis *minipipeline.WebAnalysis, info io.Writer) { + // Implementation note: we care about cases in which we don't have a final response + // to compare to and we have unexplained failures. We define "unexplained failure" a + // failure for which there's no corresponding control information. If we have test + // helper information telling us that the control server could fetch the final webpage + // then we can turn these unexplained errors into explained errors. + + switch { + // case #1: there is a successful final response with or without control + case !analysis.HTTPFinalResponseSuccessTCPWithoutControl.IsNone(): + return + case !analysis.HTTPFinalResponseSuccessTLSWithoutControl.IsNone(): + return + case !analysis.HTTPFinalResponseSuccessTLSWithControl.IsNone(): + return + case !analysis.HTTPFinalResponseSuccessTCPWithControl.IsNone(): + return + + // case #2: no final response, which is what we care about + default: + // fallthrough + } + + // we care about cases in which the TH succeeded + if analysis.ControlFinalResponseExpectations.IsNone() { + return + } + expect := analysis.ControlFinalResponseExpectations.Unwrap() + if expect.Failure.IsNone() { + return + } + if expect.Failure.Unwrap() != "" { + return + } + + // okay, now we're in business and we can explain what happened + // + // these cases are NOT MUTUALLY EXCLUSIVE because we may have different + // DNS lookups or endpoints failing in different ways here + if failures := analysis.DNSLookupUnexplainedFailure; failures.Len() > 0 { + tk.BlockingFlags |= AnalysisBlockingFlagDNSBlocking + fmt.Fprintf( + info, "- transactions with unexplained DNS lookup failures and successful control: %s\n", + failures.String(), + ) + } + + if failures := analysis.TCPConnectUnexplainedFailure; failures.Len() > 0 { + tk.BlockingFlags |= AnalysisBlockingFlagTCPIPBlocking + fmt.Fprintf( + info, "- transactions with unexplained TCP connect failures and successful control: %s\n", + failures.String(), + ) + } + + if failures := analysis.TLSHandshakeUnexplainedFailure; failures.Len() > 0 { + tk.BlockingFlags |= AnalysisBlockingFlagTLSBlocking + fmt.Fprintf( + info, "- transactions with unexplained TLS handshake failures and successful control: %s\n", + failures.String(), + ) + } + + if failures := analysis.HTTPRoundTripUnexplainedFailure; failures.Len() > 0 { + tk.BlockingFlags |= AnalysisBlockingFlagHTTPBlocking + fmt.Fprintf( + info, "- transactions with unexplained HTTP round trip failures and successful control: %s\n", + failures.String(), + ) + } +} diff --git a/internal/experiment/webconnectivitylte/analysishttpdiff.go b/internal/experiment/webconnectivitylte/analysishttpdiff.go index 6e724e9096..17ca5c8c85 100644 --- a/internal/experiment/webconnectivitylte/analysishttpdiff.go +++ b/internal/experiment/webconnectivitylte/analysishttpdiff.go @@ -11,10 +11,71 @@ import ( "github.com/ooni/probe-cli/v3/internal/experiment/webconnectivity" "github.com/ooni/probe-cli/v3/internal/measurexlite" + "github.com/ooni/probe-cli/v3/internal/minipipeline" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/optional" "github.com/ooni/probe-cli/v3/internal/runtimex" ) +// analysisHTTPDiffStatus contains the status relevant to compute HTTP diff. +type analysisHTTPDiffStatus struct { + BodyProportion optional.Value[float64] `json:"body_proportion"` + BodyLengthMatch optional.Value[bool] `json:"body_length_match"` + HeadersMatch optional.Value[bool] `json:"headers_match"` + StatusCodeMatch optional.Value[bool] `json:"status_code_match"` + TitleMatch optional.Value[bool] `json:"title_match"` +} + +// newAnalysisHTTPDiffStatus constructs a new [*analysisHTTPDiffStatus]. +func newAnalysisHTTPDiffStatus(analysis *minipipeline.WebAnalysis) *analysisHTTPDiffStatus { + hds := &analysisHTTPDiffStatus{} + + // BodyProportion & BodyLengthMatch + const bodyProportionFactor = 0.7 + if !analysis.HTTPFinalResponseDiffBodyProportionFactor.IsNone() { + hds.BodyProportion = analysis.HTTPFinalResponseDiffBodyProportionFactor + value := hds.BodyProportion.Unwrap() > bodyProportionFactor + hds.BodyLengthMatch = optional.Some(value) + } + + // HeadersMatch + if !analysis.HTTPFinalResponseDiffUncommonHeadersIntersection.IsNone() { + value := len(analysis.HTTPFinalResponseDiffUncommonHeadersIntersection.Unwrap()) > 0 + hds.HeadersMatch = optional.Some(value) + } + + // StatusCodeMatch + if !analysis.HTTPFinalResponseDiffStatusCodeMatch.IsNone() { + value := analysis.HTTPFinalResponseDiffStatusCodeMatch.Unwrap() + hds.StatusCodeMatch = optional.Some(value) + } + + // TitleMatch + if !analysis.HTTPFinalResponseDiffTitleDifferentLongWords.IsNone() { + value := len(analysis.HTTPFinalResponseDiffTitleDifferentLongWords.Unwrap()) <= 0 + hds.TitleMatch = optional.Some(value) + } + + return hds +} + +// httpDiff computes whether there is HTTP diff. +func (hds *analysisHTTPDiffStatus) httpDiff() bool { + if !hds.StatusCodeMatch.IsNone() && hds.StatusCodeMatch.Unwrap() { + if !hds.BodyLengthMatch.IsNone() && hds.BodyLengthMatch.Unwrap() { + return false + } + if !hds.HeadersMatch.IsNone() && hds.HeadersMatch.Unwrap() { + return false + } + if !hds.TitleMatch.IsNone() && hds.TitleMatch.Unwrap() { + return false + } + // fallthrough + } + return true +} + // analysisHTTPDiff computes the HTTP diff between the final request-response // observed by the probe and the TH's result. The caller is responsible of passing // us a valid probe observation and a valid TH observation with nil failure. diff --git a/internal/experiment/webconnectivitylte/measurer.go b/internal/experiment/webconnectivitylte/measurer.go index 8ef38b8b04..bfa7121aec 100644 --- a/internal/experiment/webconnectivitylte/measurer.go +++ b/internal/experiment/webconnectivitylte/measurer.go @@ -37,7 +37,7 @@ func (m *Measurer) ExperimentName() string { // ExperimentVersion implements model.ExperimentMeasurer. func (m *Measurer) ExperimentVersion() string { - return "0.5.27" + return "0.5.28" } // Run implements model.ExperimentMeasurer. diff --git a/internal/experiment/webconnectivityqa/control.go b/internal/experiment/webconnectivityqa/control.go index c68e52bdf1..fb6378d345 100644 --- a/internal/experiment/webconnectivityqa/control.go +++ b/internal/experiment/webconnectivityqa/control.go @@ -89,8 +89,9 @@ func controlFailureWithSuccessfulHTTPSWebsite() *TestCase { ExpectErr: false, ExpectTestKeys: &testKeys{ ControlFailure: "unknown_failure: httpapi: all endpoints failed: [ connection_reset; connection_reset; connection_reset; connection_reset;]", - XStatus: 1, // StatusSuccessSecure - XNullNullFlags: 8, // analysisFlagNullNullSuccessfulHTTPS + XStatus: 1, // StatusSuccessSecure + XBlockingFlags: 32, // AnalysisBlockingFlagSuccess + XNullNullFlags: 8, // analysisFlagNullNullSuccessfulHTTPS Accessible: true, Blocking: false, }, diff --git a/internal/experiment/webconnectivityqa/dnsblocking.go b/internal/experiment/webconnectivityqa/dnsblocking.go index f5ef06fcdc..207c248a92 100644 --- a/internal/experiment/webconnectivityqa/dnsblocking.go +++ b/internal/experiment/webconnectivityqa/dnsblocking.go @@ -79,7 +79,7 @@ func dnsBlockingBOGON() *TestCase { DNSExperimentFailure: nil, DNSConsistency: "inconsistent", XStatus: 4256, // StatusExperimentConnect | StatusAnomalyConnect | StatusAnomalyDNS - XDNSFlags: 1, // AnalysisFlagDNSBogon + XDNSFlags: 5, // AnalysisFlagDNSBogon | AnalysisDNSFlagUnexpectedAddrs XBlockingFlags: 33, // AnalysisBlockingFlagDNSBlocking | AnalysisBlockingFlagSuccess Accessible: false, Blocking: "dns", diff --git a/internal/experiment/webconnectivityqa/dnshijacking.go b/internal/experiment/webconnectivityqa/dnshijacking.go index 131c7a445e..dc7e29e30c 100644 --- a/internal/experiment/webconnectivityqa/dnshijacking.go +++ b/internal/experiment/webconnectivityqa/dnshijacking.go @@ -33,9 +33,9 @@ func dnsHijackingToProxyWithHTTPURL() *TestCase { StatusCodeMatch: true, HeadersMatch: true, TitleMatch: true, - XStatus: 2, // StatusSuccessCleartext - XDNSFlags: 0, - XBlockingFlags: 32, // AnalysisBlockingFlagSuccess + XStatus: 2, // StatusSuccessCleartext + XDNSFlags: 4, // AnalysisDNSFlagUnexpectedAddrs + XBlockingFlags: 33, // AnalysisBlockingFlagDNSBlocking | AnalysisBlockingFlagSuccess Accessible: true, Blocking: false, }, @@ -70,9 +70,9 @@ func dnsHijackingToProxyWithHTTPSURL() *TestCase { StatusCodeMatch: true, HeadersMatch: true, TitleMatch: true, - XStatus: 1, // StatusSuccessSecure - XDNSFlags: 0, - XBlockingFlags: 32, // AnalysisBlockingFlagSuccess + XStatus: 1, // StatusSuccessSecure + XDNSFlags: 4, // AnalysisDNSFlagUnexpectedAddrs + XBlockingFlags: 33, // AnalysisBlockingFlagDNSBlocking | AnalysisBlockingFlagSuccess Accessible: true, Blocking: false, }, diff --git a/internal/experiment/webconnectivityqa/httpdiff.go b/internal/experiment/webconnectivityqa/httpdiff.go index 29135a59ae..5090f250a8 100644 --- a/internal/experiment/webconnectivityqa/httpdiff.go +++ b/internal/experiment/webconnectivityqa/httpdiff.go @@ -92,7 +92,7 @@ func httpDiffWithInconsistentDNS() *TestCase { TitleMatch: false, XStatus: 96, // StatusAnomalyHTTPDiff | StatusAnomalyDNS XDNSFlags: 4, // AnalysisDNSFlagUnexpectedAddrs - XBlockingFlags: 35, // AnalysisBlockingFlagSuccess | AnalysisBlockingFlagDNSBlocking | AnalysisBlockingFlagTCPIPBlocking + XBlockingFlags: 17, // AnalysisBlockingFlagDNSBlocking | AnalysisBlockingFlagHTTPDiff Accessible: false, Blocking: "dns", }, diff --git a/internal/experiment/webconnectivityqa/redirect.go b/internal/experiment/webconnectivityqa/redirect.go index bff388f68e..25d6c7cad1 100644 --- a/internal/experiment/webconnectivityqa/redirect.go +++ b/internal/experiment/webconnectivityqa/redirect.go @@ -37,7 +37,7 @@ func redirectWithConsistentDNSAndThenConnectionRefusedForHTTP() *TestCase { HTTPExperimentFailure: "connection_refused", XStatus: 8320, // StatusExperimentHTTP | StatusAnomalyConnect XDNSFlags: 0, - XBlockingFlags: 32, // AnalysisBlockingFlagSuccess + XBlockingFlags: 2, // AnalysisBlockingFlagTCPIPBlocking Accessible: false, Blocking: "http-failure", }, @@ -75,7 +75,7 @@ func redirectWithConsistentDNSAndThenConnectionRefusedForHTTPS() *TestCase { HTTPExperimentFailure: "connection_refused", XStatus: 8320, // StatusExperimentHTTP | StatusAnomalyConnect XDNSFlags: 0, - XBlockingFlags: 32, // AnalysisBlockingFlagSuccess + XBlockingFlags: 2, // AnalysisBlockingFlagTCPIPBlocking Accessible: false, Blocking: "http-failure", }, @@ -113,7 +113,7 @@ func redirectWithConsistentDNSAndThenConnectionResetForHTTP() *TestCase { HTTPExperimentFailure: "connection_reset", XStatus: 8448, // StatusExperimentHTTP | StatusAnomalyReadWrite XDNSFlags: 0, - XBlockingFlags: 8, // AnalysisBlockingFlagHTTPBlocking + XBlockingFlags: 12, // AnalysisBlockingFlagTLSBlocking | AnalysisBlockingFlagHTTPBlocking Accessible: false, Blocking: "http-failure", }, @@ -151,7 +151,7 @@ func redirectWithConsistentDNSAndThenConnectionResetForHTTPS() *TestCase { HTTPExperimentFailure: "connection_reset", XStatus: 8448, // StatusExperimentHTTP | StatusAnomalyReadWrite XDNSFlags: 0, - XBlockingFlags: 8, // AnalysisBlockingFlagHTTPBlocking + XBlockingFlags: 4, // AnalysisBlockingFlagTLSBlocking Accessible: false, Blocking: "http-failure", }, @@ -182,7 +182,7 @@ func redirectWithConsistentDNSAndThenNXDOMAIN() *TestCase { HTTPExperimentFailure: "dns_nxdomain_error", XStatus: 8224, // StatusExperimentHTTP | StatusAnomalyDNS XDNSFlags: 0, - XBlockingFlags: 8, // AnalysisBlockingFlagHTTPBlocking + XBlockingFlags: 1, // AnalysisBlockingFlagDNSBlocking Accessible: false, Blocking: "dns", }, @@ -220,7 +220,7 @@ func redirectWithConsistentDNSAndThenEOFForHTTP() *TestCase { HTTPExperimentFailure: "eof_error", XStatus: 8448, // StatusExperimentHTTP | StatusAnomalyReadWrite XDNSFlags: 0, - XBlockingFlags: 8, // AnalysisBlockingFlagHTTPBlocking + XBlockingFlags: 12, // AnalysisBlockingFlagTLSBlocking | AnalysisBlockingFlagHTTPBlocking Accessible: false, Blocking: "http-failure", }, @@ -258,7 +258,7 @@ func redirectWithConsistentDNSAndThenEOFForHTTPS() *TestCase { HTTPExperimentFailure: "eof_error", XStatus: 8448, // StatusExperimentHTTP | StatusAnomalyReadWrite XDNSFlags: 0, - XBlockingFlags: 32, // AnalysisBlockingFlagSuccess + XBlockingFlags: 4, // AnalysisBlockingFlagTLSBlocking Accessible: false, Blocking: "http-failure", }, @@ -297,7 +297,7 @@ func redirectWithConsistentDNSAndThenTimeoutForHTTP() *TestCase { HTTPExperimentFailure: "generic_timeout_error", XStatus: 8704, // StatusExperimentHTTP | StatusAnomalyUnknown XDNSFlags: 0, - XBlockingFlags: 8, // AnalysisBlockingFlagHTTPBlocking + XBlockingFlags: 12, // AnalysisBlockingFlagTLSBlocking | AnalysisBlockingFlagHTTPBlocking Accessible: false, Blocking: "http-failure", }, @@ -336,7 +336,7 @@ func redirectWithConsistentDNSAndThenTimeoutForHTTPS() *TestCase { HTTPExperimentFailure: "generic_timeout_error", XStatus: 8704, // StatusExperimentHTTP | StatusAnomalyUnknown XDNSFlags: 0, - XBlockingFlags: 32, // AnalysisBlockingFlagSuccess + XBlockingFlags: 4, // AnalysisBlockingFlagTLSBlocking Accessible: false, Blocking: "http-failure", }, diff --git a/internal/experiment/webconnectivityqa/run_test.go b/internal/experiment/webconnectivityqa/run_test.go index b0e93e7efa..6adf371394 100644 --- a/internal/experiment/webconnectivityqa/run_test.go +++ b/internal/experiment/webconnectivityqa/run_test.go @@ -208,7 +208,7 @@ func TestRunTestCase(t *testing.T) { return "web_connectivity" }, MockExperimentVersion: func() string { - return "0.5.27" + return "0.5.28" }, MockRun: func(ctx context.Context, args *model.ExperimentArgs) error { args.Measurement.TestKeys = &testKeys{ @@ -244,7 +244,7 @@ func TestRunTestCase(t *testing.T) { return "web_connectivity" }, MockExperimentVersion: func() string { - return "0.5.27" + return "0.5.28" }, MockRun: func(ctx context.Context, args *model.ExperimentArgs) error { args.Measurement.TestKeys = &testKeys{ @@ -282,7 +282,7 @@ func TestRunTestCase(t *testing.T) { return "web_connectivity" }, MockExperimentVersion: func() string { - return "0.5.27" + return "0.5.28" }, MockRun: func(ctx context.Context, args *model.ExperimentArgs) error { args.Measurement.TestKeys = &testKeys{ @@ -320,7 +320,7 @@ func TestRunTestCase(t *testing.T) { return "web_connectivity" }, MockExperimentVersion: func() string { - return "0.5.27" + return "0.5.28" }, MockRun: func(ctx context.Context, args *model.ExperimentArgs) error { args.Measurement.TestKeys = &testKeys{ @@ -390,7 +390,7 @@ func TestRunTestCase(t *testing.T) { return "web_connectivity" }, MockExperimentVersion: func() string { - return "0.5.27" + return "0.5.28" }, MockRun: func(ctx context.Context, args *model.ExperimentArgs) error { args.Measurement.TestKeys = &testKeys{ diff --git a/internal/experiment/webconnectivityqa/testkeys.go b/internal/experiment/webconnectivityqa/testkeys.go index 008c893d6a..35508bdded 100644 --- a/internal/experiment/webconnectivityqa/testkeys.go +++ b/internal/experiment/webconnectivityqa/testkeys.go @@ -73,12 +73,12 @@ func compareTestKeys(expected, got *testKeys) error { // ignore the fields that are specific to LTE options = append(options, cmpopts.IgnoreFields(testKeys{}, "XDNSFlags", "XBlockingFlags", "XNullNullFlags")) - case "0.5.27": + case "0.5.28": // ignore the fields that are specific to v0.4 options = append(options, cmpopts.IgnoreFields(testKeys{}, "XStatus")) - // TODO(bassosimone): these flags are specific of the "orig" analysis engine - options = append(options, cmpopts.IgnoreFields(testKeys{}, "XDNSFlags", "XBlockingFlags", "XNullNullFlags")) + // TODO(bassosimone): ignore fields used by the v0.5 "orig" local analysis engine + options = append(options, cmpopts.IgnoreFields(testKeys{}, "XNullNullFlags")) default: return fmt.Errorf("unknown experiment version: %s", got.XExperimentVersion)