From e3590c3c1d9d89fb02ec534cd773774917d36599 Mon Sep 17 00:00:00 2001 From: Mansi Nahar Date: Thu, 26 Aug 2021 11:00:34 -0400 Subject: [PATCH] Update iOS version parsing for LMT tracking to accept major.minor.patch format as well (#1978) --- go.mod | 1 + go.sum | 2 + privacy/lmt/ios_test.go | 48 +++++++++++++++++++ util/iosutil/iosutil.go | 28 ++++++----- util/iosutil/iosutil_test.go | 92 ++++++++++++++++++++++++++++++++++-- 5 files changed, 155 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index d003abae24d..6c6f32090ba 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/influxdata/influxdb v1.6.1 github.com/julienschmidt/httprouter v1.1.0 + github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect github.com/lib/pq v1.0.0 github.com/magiconair/properties v1.8.5 github.com/mattn/go-colorable v0.1.2 // indirect diff --git a/go.sum b/go.sum index 343bcf0d8f8..6db57ada702 100644 --- a/go.sum +++ b/go.sum @@ -205,6 +205,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.1.0 h1:7wLdtIiIpzOkC9u6sXOozpBauPdskj3ru4EI5MABq68= github.com/julienschmidt/httprouter v1.1.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= diff --git a/privacy/lmt/ios_test.go b/privacy/lmt/ios_test.go index 2caec1be64c..af72cf08f23 100644 --- a/privacy/lmt/ios_test.go +++ b/privacy/lmt/ios_test.go @@ -32,6 +32,54 @@ func TestModifyForIOS(t *testing.T) { }, expectedLMT: openrtb2.Int8Ptr(1), }, + { + description: "14.1", + givenRequest: &openrtb2.BidRequest{ + App: &openrtb2.App{}, + Device: &openrtb2.Device{OS: "iOS", OSV: "14.1", IFA: "", Lmt: nil}, + }, + expectedLMT: openrtb2.Int8Ptr(1), + }, + { + description: "14.1.3", + givenRequest: &openrtb2.BidRequest{ + App: &openrtb2.App{}, + Device: &openrtb2.Device{OS: "iOS", OSV: "14.1.3", IFA: "", Lmt: nil}, + }, + expectedLMT: openrtb2.Int8Ptr(1), + }, + { + description: "14.2", + givenRequest: &openrtb2.BidRequest{ + App: &openrtb2.App{}, + Device: &openrtb2.Device{Ext: json.RawMessage(`{"atts":0}`), OS: "iOS", OSV: "14.2", IFA: "", Lmt: nil}, + }, + expectedLMT: openrtb2.Int8Ptr(0), + }, + { + description: "14.2", + givenRequest: &openrtb2.BidRequest{ + App: &openrtb2.App{}, + Device: &openrtb2.Device{Ext: json.RawMessage(`{"atts":2}`), OS: "iOS", OSV: "14.2", IFA: "", Lmt: openrtb2.Int8Ptr(0)}, + }, + expectedLMT: openrtb2.Int8Ptr(1), + }, + { + description: "14.2.7", + givenRequest: &openrtb2.BidRequest{ + App: &openrtb2.App{}, + Device: &openrtb2.Device{Ext: json.RawMessage(`{"atts":1}`), OS: "iOS", OSV: "14.2.7", IFA: "", Lmt: nil}, + }, + expectedLMT: openrtb2.Int8Ptr(1), + }, + { + description: "14.2.7", + givenRequest: &openrtb2.BidRequest{ + App: &openrtb2.App{}, + Device: &openrtb2.Device{Ext: json.RawMessage(`{"atts":3}`), OS: "iOS", OSV: "14.2.7", IFA: "", Lmt: openrtb2.Int8Ptr(1)}, + }, + expectedLMT: openrtb2.Int8Ptr(0), + }, } for _, test := range testCases { diff --git a/util/iosutil/iosutil.go b/util/iosutil/iosutil.go index 19d7c53d99a..86add49cede 100644 --- a/util/iosutil/iosutil.go +++ b/util/iosutil/iosutil.go @@ -16,8 +16,8 @@ type Version struct { func ParseVersion(v string) (Version, error) { parts := strings.Split(v, ".") - if len(parts) != 2 { - return Version{}, errors.New("expected major.minor format") + if len(parts) < 2 || len(parts) > 3 { + return Version{}, errors.New("expected either major.minor or major.minor.patch format") } major, err := strconv.Atoi(parts[0]) @@ -37,6 +37,15 @@ func ParseVersion(v string) (Version, error) { return version, nil } +// Equal returns true if the iOS device version is equal to the desired major and minor version, using semantic versioning. +func (v Version) Equal(major, minor int) bool { + if v.Major == major { + return v.Minor == minor + } + + return false +} + // EqualOrGreater returns true if the iOS device version is equal or greater to the desired version, using semantic versioning. func (v Version) EqualOrGreater(major, minor int) bool { if v.Major == major { @@ -59,20 +68,17 @@ const ( // DetectVersionClassification detects the iOS version classification. func DetectVersionClassification(v string) VersionClassification { - // exact comparisons first. no parsing required. - if v == "14.0" { - return Version140 - } - if v == "14.1" { - return Version141 - } - // semantic versioning comparison second. parsing required. if iosVersion, err := ParseVersion(v); err == nil { + if iosVersion.Equal(14, 0) { + return Version140 + } + if iosVersion.Equal(14, 1) { + return Version141 + } if iosVersion.EqualOrGreater(14, 2) { return Version142OrGreater } } - return VersionUnknown } diff --git a/util/iosutil/iosutil_test.go b/util/iosutil/iosutil_test.go index 2103760c1dc..290b16ad559 100644 --- a/util/iosutil/iosutil_test.go +++ b/util/iosutil/iosutil_test.go @@ -14,24 +14,34 @@ func TestParseVersion(t *testing.T) { expectedError string }{ { - description: "Valid", + description: "Valid - major.minor format", given: "14.2", expectedVersion: Version{Major: 14, Minor: 2}, }, + { + description: "Valid - major.minor.patch format", + given: "14.2.1", + expectedVersion: Version{Major: 14, Minor: 2}, + }, { description: "Invalid Parts - Empty", given: "", - expectedError: "expected major.minor format", + expectedError: "expected either major.minor or major.minor.patch format", }, { description: "Invalid Parts - Too Few", given: "14", - expectedError: "expected major.minor format", + expectedError: "expected either major.minor or major.minor.patch format", }, { description: "Invalid Parts - Too Many", - given: "14.2.1", - expectedError: "expected major.minor format", + given: "14.2.1.3", + expectedError: "expected either major.minor or major.minor.patch format", + }, + { + description: "Invalid Parts - Too Few", + given: "14", + expectedError: "expected either major.minor or major.minor.patch format", }, { description: "Invalid Major", @@ -110,6 +120,58 @@ func TestEqualOrGreater(t *testing.T) { } } +func TestEqual(t *testing.T) { + givenMajor := 14 + givenMinor := 2 + + tests := []struct { + description string + givenVersion Version + expected bool + }{ + { + description: "Less Than By Major + Minor", + givenVersion: Version{Major: 13, Minor: 1}, + expected: false, + }, + { + description: "Less Than By Major", + givenVersion: Version{Major: 13, Minor: 2}, + expected: false, + }, + { + description: "Less Than By Minor", + givenVersion: Version{Major: 14, Minor: 1}, + expected: false, + }, + { + description: "Equal", + givenVersion: Version{Major: 14, Minor: 2}, + expected: true, + }, + { + description: "Greater By Major + Minor", + givenVersion: Version{Major: 15, Minor: 3}, + expected: false, + }, + { + description: "Greater By Major", + givenVersion: Version{Major: 15, Minor: 2}, + expected: false, + }, + { + description: "Greater By Minor", + givenVersion: Version{Major: 14, Minor: 3}, + expected: false, + }, + } + + for _, test := range tests { + result := test.givenVersion.Equal(givenMajor, givenMinor) + assert.Equal(t, test.expected, result, test.description) + } +} + func TestDetectVersionClassification(t *testing.T) { tests := []struct { @@ -124,22 +186,42 @@ func TestDetectVersionClassification(t *testing.T) { given: "14.0", expected: Version140, }, + { + given: "14.0.1", + expected: Version140, + }, { given: "14.1", expected: Version141, }, + { + given: "14.1.2", + expected: Version141, + }, { given: "14.2", expected: Version142OrGreater, }, + { + given: "14.2.3", + expected: Version142OrGreater, + }, { given: "14.3", expected: Version142OrGreater, }, + { + given: "14.3.2", + expected: Version142OrGreater, + }, { given: "15.0", expected: Version142OrGreater, }, + { + given: "15.0.1", + expected: Version142OrGreater, + }, } for _, test := range tests {