From 41bedb59db4dc3bc06b18656d9ec7738cb9163cc Mon Sep 17 00:00:00 2001 From: Simone Basso Date: Fri, 19 Jan 2024 13:38:38 +0100 Subject: [PATCH] feat(webconnectivitylte): classic computes XBlockingFlags (#1446) This diff modifies the "classic" analysis engine to compute XBlockingFlags. While there, make sure that the flags we compute make sense thus fixing analysis bugs in the previously used "orig" engine. Part of https://github.com/ooni/probe/issues/2640. --- .../webconnectivitylte/analysisclassic.go | 25 +- .../webconnectivitylte/analysisext.go | 223 ++++++++++++++++++ .../webconnectivitylte/analysishttpdiff.go | 61 +++++ .../experiment/webconnectivitylte/measurer.go | 2 +- .../experiment/webconnectivityqa/control.go | 5 +- .../webconnectivityqa/dnsblocking.go | 2 +- .../webconnectivityqa/dnshijacking.go | 12 +- .../experiment/webconnectivityqa/httpdiff.go | 2 +- .../experiment/webconnectivityqa/redirect.go | 18 +- .../experiment/webconnectivityqa/run_test.go | 10 +- .../experiment/webconnectivityqa/testkeys.go | 6 +- 11 files changed, 332 insertions(+), 34 deletions(-) create mode 100644 internal/experiment/webconnectivitylte/analysisext.go 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)