Skip to content

Commit

Permalink
Adds VPN PPro pixels. Makes sure tests all run in App Store target too
Browse files Browse the repository at this point in the history
  • Loading branch information
diegoreymendez committed Mar 21, 2024
1 parent cb3b645 commit 65fa647
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 2 deletions.
21 changes: 21 additions & 0 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2261,6 +2261,9 @@
7BA076BB2B65D61400D7FB72 /* NetworkProtectionProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 7BA076BA2B65D61400D7FB72 /* NetworkProtectionProxy */; };
7BA4727D26F01BC400EAA165 /* CoreDataTestUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292C42667104B00AD2C21 /* CoreDataTestUtilities.swift */; };
7BA59C9B2AE18B49009A97B1 /* SystemExtensionManager in Frameworks */ = {isa = PBXBuildFile; productRef = 7BA59C9A2AE18B49009A97B1 /* SystemExtensionManager */; };
7BA75D6D2BAC4D9400AC79B2 /* VPNPrivacyPro in Frameworks */ = {isa = PBXBuildFile; productRef = 7BA75D6C2BAC4D9400AC79B2 /* VPNPrivacyPro */; };
7BA75D6F2BAC4D9B00AC79B2 /* VPNPrivacyPro in Frameworks */ = {isa = PBXBuildFile; productRef = 7BA75D6E2BAC4D9B00AC79B2 /* VPNPrivacyPro */; };
7BA75D712BAC4DA000AC79B2 /* VPNPrivacyPro in Frameworks */ = {isa = PBXBuildFile; productRef = 7BA75D702BAC4DA000AC79B2 /* VPNPrivacyPro */; };
7BA7CC392AD11E2D0042E5CE /* DuckDuckGoVPNAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BA7CC0E2AD11DC80042E5CE /* DuckDuckGoVPNAppDelegate.swift */; };
7BA7CC3A2AD11E2D0042E5CE /* DuckDuckGoVPNAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BA7CC0E2AD11DC80042E5CE /* DuckDuckGoVPNAppDelegate.swift */; };
7BA7CC3D2AD11E380042E5CE /* TunnelControllerIPCService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BA7CC112AD11DC80042E5CE /* TunnelControllerIPCService.swift */; };
Expand Down Expand Up @@ -4684,6 +4687,7 @@
4BF97AD32B43C43F00EB4240 /* NetworkProtectionUI in Frameworks */,
7B1459572B7D43E500047F2C /* NetworkProtectionProxy in Frameworks */,
B6F7128229F6820A00594A45 /* QuickLookUI.framework in Frameworks */,
7BA75D6F2BAC4D9B00AC79B2 /* VPNPrivacyPro in Frameworks */,
984FD3BF299ACF35007334DD /* Bookmarks in Frameworks */,
37A5E2F0298AA1B20047046B /* Persistence in Frameworks */,
9DC70B1A2AA1FA5B005A844B /* LoginItems in Frameworks */,
Expand Down Expand Up @@ -4838,6 +4842,7 @@
4B957BE22AC7AE700062CA31 /* Sparkle in Frameworks */,
373FB4B52B4D6C57004C88D6 /* PreferencesViews in Frameworks */,
4B957BE32AC7AE700062CA31 /* Navigation in Frameworks */,
7BA75D712BAC4DA000AC79B2 /* VPNPrivacyPro in Frameworks */,
1E21F8E32B73E48600FB272E /* Subscription in Frameworks */,
4B957BE42AC7AE700062CA31 /* DDGSync in Frameworks */,
4B957BE52AC7AE700062CA31 /* OpenSSL in Frameworks */,
Expand Down Expand Up @@ -4924,6 +4929,7 @@
37269EFB2B332F9E005E8E46 /* Common in Frameworks */,
4B2AAAF529E70DEA0026AFC0 /* Lottie in Frameworks */,
AA06B6B72672AF8100F541C5 /* Sparkle in Frameworks */,
7BA75D6D2BAC4D9400AC79B2 /* VPNPrivacyPro in Frameworks */,
1EA7B8D52B7E078C000330A4 /* Subscription in Frameworks */,
B6B77BE8297973D4001E68A1 /* Navigation in Frameworks */,
3739326729AE4B42009346AE /* DDGSync in Frameworks */,
Expand Down Expand Up @@ -8707,6 +8713,7 @@
4BCBE4572BA7E17800FC75A1 /* SubscriptionUI */,
85D44B872BA08D30001B4AB5 /* Suggestions */,
4BCBE4592BA7E17800FC75A1 /* Subscription */,
7BA75D6E2BAC4D9B00AC79B2 /* VPNPrivacyPro */,
);
productName = DuckDuckGo;
productReference = 3706FD05293F65D500E42796 /* DuckDuckGo App Store.app */;
Expand Down Expand Up @@ -8997,6 +9004,7 @@
85E2BBD12B8F536F00DBEC7A /* History */,
F1D43AF62B98E48F00BAB743 /* BareBonesBrowserKit */,
85D44B892BA08D3B001B4AB5 /* Suggestions */,
7BA75D702BAC4DA000AC79B2 /* VPNPrivacyPro */,
);
productName = DuckDuckGo;
productReference = 4B957C412AC7AE700062CA31 /* DuckDuckGo Privacy Pro.app */;
Expand Down Expand Up @@ -9167,6 +9175,7 @@
1EA7B8D42B7E078C000330A4 /* Subscription */,
F1D43AF22B98E47800BAB743 /* BareBonesBrowserKit */,
85D44B852BA08D29001B4AB5 /* Suggestions */,
7BA75D6C2BAC4D9400AC79B2 /* VPNPrivacyPro */,
);
productName = DuckDuckGo;
productReference = AA585D7E248FD31100E9A3E2 /* DuckDuckGo.app */;
Expand Down Expand Up @@ -14612,6 +14621,18 @@
isa = XCSwiftPackageProductDependency;
productName = SystemExtensionManager;
};
7BA75D6C2BAC4D9400AC79B2 /* VPNPrivacyPro */ = {
isa = XCSwiftPackageProductDependency;
productName = VPNPrivacyPro;
};
7BA75D6E2BAC4D9B00AC79B2 /* VPNPrivacyPro */ = {
isa = XCSwiftPackageProductDependency;
productName = VPNPrivacyPro;
};
7BA75D702BAC4DA000AC79B2 /* VPNPrivacyPro */ = {
isa = XCSwiftPackageProductDependency;
productName = VPNPrivacyPro;
};
7BA7CC5E2AD1210C0042E5CE /* Networking */ = {
isa = XCSwiftPackageProductDependency;
package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,26 @@
ReferencedContainer = "container:LocalPackages/PixelKit">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "VPNPrivacyProTests"
BuildableName = "VPNPrivacyProTests"
BlueprintName = "VPNPrivacyProTests"
ReferencedContainer = "container:LocalPackages/NetworkProtectionMac">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "NetworkProtectionUITests"
BuildableName = "NetworkProtectionUITests"
BlueprintName = "NetworkProtectionUITests"
ReferencedContainer = "container:LocalPackages/NetworkProtectionMac">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,16 @@
ReferencedContainer = "container:LocalPackages/DataBrokerProtection">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "VPNPrivacyProTests"
BuildableName = "VPNPrivacyProTests"
BlueprintName = "VPNPrivacyProTests"
ReferencedContainer = "container:LocalPackages/NetworkProtectionMac">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
// limitations under the License.
//

import AppKit
import Foundation
import PixelKit
import VPNPrivacyPro

final class WaitlistThankYouPromptPresenter {

Expand Down Expand Up @@ -65,6 +68,8 @@ final class WaitlistThankYouPromptPresenter {

@MainActor
func presentVPNThankYouPrompt(in window: NSWindow) {
PixelKit.fire(VPNPrivacyProPixel.vpnBetaThankYouShown)

let thankYouModalView = WaitlistBetaThankYouDialogViewController(copy: .vpn)
let thankYouWindowController = thankYouModalView.wrappedInWindowController()
if let thankYouWindow = thankYouWindowController.window {
Expand Down
29 changes: 27 additions & 2 deletions LocalPackages/NetworkProtectionMac/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ let package = Package(
products: [
.library(name: "NetworkProtectionIPC", targets: ["NetworkProtectionIPC"]),
.library(name: "NetworkProtectionProxy", targets: ["NetworkProtectionProxy"]),
.library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"])
.library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"]),
.library(name: "VPNPrivacyPro", targets: ["VPNPrivacyPro"])
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "128.0.0"),
Expand Down Expand Up @@ -84,6 +85,7 @@ let package = Package(
],
plugins: [.plugin(name: "SwiftLintPlugin", package: "apple-toolbox")]
),

.testTarget(
name: "NetworkProtectionUITests",
dependencies: [
Expand All @@ -92,6 +94,29 @@ let package = Package(
.product(name: "LoginItems", package: "LoginItems"),
],
plugins: [.plugin(name: "SwiftLintPlugin", package: "apple-toolbox")]
)
),

// MARK: - VPNPixels

.target(
name: "VPNPrivacyPro",
dependencies: [
.product(name: "PixelKit", package: "PixelKit"),
],
swiftSettings: [
.define("DEBUG", .when(configuration: .debug))
],
plugins: [.plugin(name: "SwiftLintPlugin", package: "apple-toolbox")]
),

.testTarget(
name: "VPNPrivacyProTests",
dependencies: [
.byName(name: "VPNPrivacyPro"),
.product(name: "PixelKit", package: "PixelKit"),
.product(name: "PixelKitTestingUtilities", package: "PixelKit"),
],
plugins: [.plugin(name: "SwiftLintPlugin", package: "apple-toolbox")]
),
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// VPNPrivacyProPixel.swift
//
// Copyright © 2024 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import PixelKit

/// PrivacyPro pixels.
///
/// Ref: https://app.asana.com/0/0/1206836019887720/f
///
public enum VPNPrivacyProPixel: PixelKitEventV2 {

/// Fired when PrivacyPro VPN access is revoked, and the dialog is shown.
///
case vpnAccessRevokedDialogShown

/// Fired only once when the VPN beta becomes disabled due to the start of PrivacyPro..
///
case vpnBetaStoppedWhenPrivacyProEnabled

/// Fired only once when the thank you alert is shown.
///
case vpnBetaThankYouShown

public var name: String {
switch self {
case .vpnAccessRevokedDialogShown:
return "vpn_access_revoked_dialog_shown"
case .vpnBetaStoppedWhenPrivacyProEnabled:
return "vpn_beta_stopped_when_privacy_pro_enabled"
case .vpnBetaThankYouShown:
return "privacy_pro_promotion_dialog_shown"
}
}

public var error: Error? {
nil
}

public var parameters: [String : String]? {

Check failure on line 55 in LocalPackages/NetworkProtectionMac/Sources/VPNPrivacyPro/Pixels/VPNPrivacyProPixel.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Colons should be next to the identifier when specifying a type and next to the key in dictionary literals (colon)
nil
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//

Check failure on line 1 in LocalPackages/NetworkProtectionMac/Tests/VPNPrivacyProTests/VPNPrivacyProPixelTests.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Header comments should be consistent with project patterns (file_header)
// VPNPrivacyProPixel.swift
//
// Copyright © 2024 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import PixelKit
import PixelKitTestingUtilities
import XCTest
@testable import VPNPrivacyPro

final class VPNPrivacyProPixelTests: XCTestCase {

private enum TestError: CustomNSError {
case testError
case underlyingError

/// The domain of the error.
static var errorDomain: String {
"testDomain"
}

/// The error code within the given domain.
var errorCode: Int {
switch self {
case .testError: return 1
case .underlyingError: return 2
}
}

/// The user-info dictionary.
var errorUserInfo: [String: Any] {
switch self {
case .testError:
return [NSUnderlyingErrorKey: TestError.underlyingError]
case .underlyingError:
return [:]
}
}
}

// MARK: - Test Firing Pixels

/// This test verifies validates expectations when firing `VPNPrivacyProPixel`.
///
/// This test verifies a few different things:
/// - That the pixel name is not changed by mistake.
/// - That when the pixel is fired its name and parameters are exactly what's expected.
///
func testVPNPixelFireExpectations() {
fire(VPNPrivacyProPixel.vpnAccessRevokedDialogShown,
and: .expect(pixelName: "m_mac_vpn_access_revoked_dialog_shown"),
file: #filePath,
line: #line)
fire(VPNPrivacyProPixel.vpnBetaStoppedWhenPrivacyProEnabled,
and: .expect(pixelName: "m_mac_vpn_beta_stopped_when_privacy_pro_enabled"),
file: #filePath,
line: #line)
fire(VPNPrivacyProPixel.vpnBetaThankYouShown,
and: .expect(pixelName: "m_mac_privacy_pro_promotion_dialog_shown"),
file: #filePath,
line: #line)
}
}

0 comments on commit 65fa647

Please sign in to comment.