Skip to content

Commit 9360468

Browse files
authored
Merge pull request #325 from openziti/add-automated-tests
Add CZitiTests unit test target with CI integration
2 parents d5157e5 + 0b9f84c commit 9360468

18 files changed

+1833
-0
lines changed

.github/workflows/CI.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,23 @@ jobs:
108108
xcodebuild build -configuration Release -scheme CZiti-macOS -derivedDataPath ./DerivedData/CZiti \
109109
-arch x86_64 -arch arm64 ONLY_ACTIVE_ARCH=NO -sdk macosx | xcpretty
110110
111+
- name: Run Tests
112+
run: |
113+
set -o pipefail
114+
xcodebuild test -scheme CZitiTests -derivedDataPath ./DerivedData/CZiti \
115+
-sdk macosx -destination 'platform=macOS' ONLY_ACTIVE_ARCH=YES | xcpretty
116+
117+
# Builds the integration test tool to catch compile regressions. End-to-end
118+
# execution against `ziti edge quickstart` is deferred until the macOS data
119+
# protection keychain / entitlement issue is resolved (see ziti-test-runner/main.swift).
120+
- name: Build ziti-test-runner
121+
run: |
122+
set -o pipefail
123+
xcodebuild build -configuration Debug -scheme ziti-test-runner \
124+
-derivedDataPath ./DerivedData/CZiti -sdk macosx \
125+
-destination 'platform=macOS' ONLY_ACTIVE_ARCH=YES \
126+
CODE_SIGNING_ALLOWED=NO | xcpretty
127+
111128
- name: Create Frameworks
112129
run: |
113130
./make_dist.sh

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
xcuserdata/
22
DerivedData/
3+
.derived-data-log-*
34
dist/
45
include/
56
build/

CZiti.xcodeproj/project.pbxproj

Lines changed: 454 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1330"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "NO"
13+
buildForArchiving = "NO"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "F14CA485E6D36A8525814631"
18+
BuildableName = "CZitiTests.xctest"
19+
BlueprintName = "CZitiTests"
20+
ReferencedContainer = "container:CZiti.xcodeproj">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
24+
</BuildAction>
25+
<TestAction
26+
buildConfiguration = "Debug"
27+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
shouldUseLaunchSchemeArgsEnv = "YES">
30+
<Testables>
31+
<TestableReference
32+
skipped = "NO">
33+
<BuildableReference
34+
BuildableIdentifier = "primary"
35+
BlueprintIdentifier = "F14CA485E6D36A8525814631"
36+
BuildableName = "CZitiTests.xctest"
37+
BlueprintName = "CZitiTests"
38+
ReferencedContainer = "container:CZiti.xcodeproj">
39+
</BuildableReference>
40+
</TestableReference>
41+
</Testables>
42+
</TestAction>
43+
<LaunchAction
44+
buildConfiguration = "Debug"
45+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
46+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
47+
launchStyle = "0"
48+
useCustomWorkingDirectory = "NO"
49+
ignoresPersistentStateOnLaunch = "NO"
50+
debugDocumentVersioning = "YES"
51+
debugServiceExtension = "internal"
52+
allowLocationSimulation = "YES">
53+
</LaunchAction>
54+
<ProfileAction
55+
buildConfiguration = "Release"
56+
shouldUseLaunchSchemeArgsEnv = "YES"
57+
savedToolIdentifier = ""
58+
useCustomWorkingDirectory = "NO"
59+
debugDocumentVersioning = "YES">
60+
</ProfileAction>
61+
<AnalyzeAction
62+
buildConfiguration = "Debug">
63+
</AnalyzeAction>
64+
<ArchiveAction
65+
buildConfiguration = "Release"
66+
revealArchiveInOrganizer = "YES">
67+
</ArchiveAction>
68+
</Scheme>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1330"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "1555C4CB437C07E562A290CA"
18+
BuildableName = "ziti-test-runner"
19+
BlueprintName = "ziti-test-runner"
20+
ReferencedContainer = "container:CZiti.xcodeproj">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
24+
</BuildAction>
25+
<TestAction
26+
buildConfiguration = "Debug"
27+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
shouldUseLaunchSchemeArgsEnv = "YES">
30+
<Testables>
31+
</Testables>
32+
</TestAction>
33+
<LaunchAction
34+
buildConfiguration = "Debug"
35+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
36+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
37+
launchStyle = "0"
38+
useCustomWorkingDirectory = "NO"
39+
ignoresPersistentStateOnLaunch = "NO"
40+
debugDocumentVersioning = "YES"
41+
debugServiceExtension = "internal"
42+
allowLocationSimulation = "YES">
43+
<BuildableProductRunnable
44+
runnableDebuggingMode = "0">
45+
<BuildableReference
46+
BuildableIdentifier = "primary"
47+
BlueprintIdentifier = "1555C4CB437C07E562A290CA"
48+
BuildableName = "ziti-test-runner"
49+
BlueprintName = "ziti-test-runner"
50+
ReferencedContainer = "container:CZiti.xcodeproj">
51+
</BuildableReference>
52+
</BuildableProductRunnable>
53+
</LaunchAction>
54+
<ProfileAction
55+
buildConfiguration = "Release"
56+
shouldUseLaunchSchemeArgsEnv = "YES"
57+
savedToolIdentifier = ""
58+
useCustomWorkingDirectory = "NO"
59+
debugDocumentVersioning = "YES">
60+
<BuildableProductRunnable
61+
runnableDebuggingMode = "0">
62+
<BuildableReference
63+
BuildableIdentifier = "primary"
64+
BlueprintIdentifier = "1555C4CB437C07E562A290CA"
65+
BuildableName = "ziti-test-runner"
66+
BlueprintName = "ziti-test-runner"
67+
ReferencedContainer = "container:CZiti.xcodeproj">
68+
</BuildableReference>
69+
</BuildableProductRunnable>
70+
</ProfileAction>
71+
<AnalyzeAction
72+
buildConfiguration = "Debug">
73+
</AnalyzeAction>
74+
<ArchiveAction
75+
buildConfiguration = "Release"
76+
revealArchiveInOrganizer = "YES">
77+
</ArchiveAction>
78+
</Scheme>

CZitiTests/EnrollModeTests.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
Copyright NetFoundry Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
import XCTest
17+
@testable import CZiti
18+
19+
class EnrollModeTests: XCTestCase {
20+
21+
func testRawValues() {
22+
XCTAssertEqual(Ziti.EnrollMode.none.rawValue, 0)
23+
XCTAssertEqual(Ziti.EnrollMode.cert.rawValue, 1)
24+
XCTAssertEqual(Ziti.EnrollMode.token.rawValue, 2)
25+
}
26+
27+
func testInitFromRawValue() {
28+
XCTAssertEqual(Ziti.EnrollMode(rawValue: 0), Ziti.EnrollMode.none)
29+
XCTAssertEqual(Ziti.EnrollMode(rawValue: 1), Ziti.EnrollMode.cert)
30+
XCTAssertEqual(Ziti.EnrollMode(rawValue: 2), Ziti.EnrollMode.token)
31+
}
32+
}

CZitiTests/JWTProviderTests.swift

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
Copyright NetFoundry Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
import XCTest
17+
@testable import CZiti
18+
19+
class JWTProviderTests: XCTestCase {
20+
21+
func testDecodeWithAllFields() throws {
22+
let json = """
23+
{"name":"My Provider","issuer":"https://auth.example.com","canCertEnroll":true,"canTokenEnroll":false}
24+
"""
25+
let provider = try JSONDecoder().decode(JWTProvider.self, from: json.data(using: .utf8)!)
26+
27+
XCTAssertEqual(provider.name, "My Provider")
28+
XCTAssertEqual(provider.issuer, "https://auth.example.com")
29+
XCTAssertTrue(provider.canCertEnroll)
30+
XCTAssertFalse(provider.canTokenEnroll)
31+
}
32+
33+
func testDecodeMissingBooleanKeysDefaultToFalse() throws {
34+
// This is the bug scenario from old .zid files that lacked these keys
35+
let json = """
36+
{"name":"Legacy Provider","issuer":"https://old.example.com"}
37+
"""
38+
let provider = try JSONDecoder().decode(JWTProvider.self, from: json.data(using: .utf8)!)
39+
40+
XCTAssertEqual(provider.name, "Legacy Provider")
41+
XCTAssertEqual(provider.issuer, "https://old.example.com")
42+
XCTAssertFalse(provider.canCertEnroll)
43+
XCTAssertFalse(provider.canTokenEnroll)
44+
}
45+
46+
func testDecodeNullBooleanValues() throws {
47+
let json = """
48+
{"name":"Null Bools","issuer":"https://x.com","canCertEnroll":null,"canTokenEnroll":null}
49+
"""
50+
let provider = try JSONDecoder().decode(JWTProvider.self, from: json.data(using: .utf8)!)
51+
52+
XCTAssertFalse(provider.canCertEnroll)
53+
XCTAssertFalse(provider.canTokenEnroll)
54+
}
55+
56+
func testDecodeBothBooleansTrue() throws {
57+
let json = """
58+
{"name":"Full","issuer":"https://x.com","canCertEnroll":true,"canTokenEnroll":true}
59+
"""
60+
let provider = try JSONDecoder().decode(JWTProvider.self, from: json.data(using: .utf8)!)
61+
62+
XCTAssertTrue(provider.canCertEnroll)
63+
XCTAssertTrue(provider.canTokenEnroll)
64+
}
65+
66+
func testCodableRoundTrip() throws {
67+
let json = """
68+
{"name":"Round Trip","issuer":"https://rt.example.com","canCertEnroll":true,"canTokenEnroll":false}
69+
"""
70+
let original = try JSONDecoder().decode(JWTProvider.self, from: json.data(using: .utf8)!)
71+
72+
let encoded = try JSONEncoder().encode(original)
73+
let decoded = try JSONDecoder().decode(JWTProvider.self, from: encoded)
74+
75+
XCTAssertEqual(decoded.name, original.name)
76+
XCTAssertEqual(decoded.issuer, original.issuer)
77+
XCTAssertEqual(decoded.canCertEnroll, original.canCertEnroll)
78+
XCTAssertEqual(decoded.canTokenEnroll, original.canTokenEnroll)
79+
}
80+
81+
func testDecodePreservesExactValues() throws {
82+
// Verify encoding includes the boolean fields (so round-trip from new .zid files works)
83+
let json = """
84+
{"name":"P","issuer":"I","canCertEnroll":false,"canTokenEnroll":true}
85+
"""
86+
let provider = try JSONDecoder().decode(JWTProvider.self, from: json.data(using: .utf8)!)
87+
let encoded = try JSONEncoder().encode(provider)
88+
let reDecoded = try JSONDecoder().decode(JWTProvider.self, from: encoded)
89+
90+
XCTAssertFalse(reDecoded.canCertEnroll)
91+
XCTAssertTrue(reDecoded.canTokenEnroll)
92+
}
93+
}

CZitiTests/ZitiClaimsTests.swift

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
Copyright NetFoundry Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
import XCTest
17+
@testable import CZiti
18+
19+
class ZitiClaimsTests: XCTestCase {
20+
21+
func testCodableRoundTrip() throws {
22+
let claims = ZitiClaims("subject-123", "https://issuer.example.com", "ott", 1700000000, "jwt-id-456")
23+
24+
let data = try JSONEncoder().encode(claims)
25+
let decoded = try JSONDecoder().decode(ZitiClaims.self, from: data)
26+
27+
XCTAssertEqual(decoded.sub, "subject-123")
28+
XCTAssertEqual(decoded.iss, "https://issuer.example.com")
29+
XCTAssertEqual(decoded.em, "ott")
30+
XCTAssertEqual(decoded.exp, 1700000000)
31+
XCTAssertEqual(decoded.jti, "jwt-id-456")
32+
}
33+
34+
func testAllOptionalsNil() throws {
35+
let claims = ZitiClaims("sub-only", nil, nil, nil, nil)
36+
37+
let data = try JSONEncoder().encode(claims)
38+
let decoded = try JSONDecoder().decode(ZitiClaims.self, from: data)
39+
40+
XCTAssertEqual(decoded.sub, "sub-only")
41+
XCTAssertNil(decoded.iss)
42+
XCTAssertNil(decoded.em)
43+
XCTAssertNil(decoded.exp)
44+
XCTAssertNil(decoded.jti)
45+
}
46+
47+
func testDecodeFromJSON() throws {
48+
let json = """
49+
{"sub":"identity-abc","iss":"https://ctrl:1280","em":"ott","exp":9999999999,"jti":"jti-xyz"}
50+
"""
51+
let decoded = try JSONDecoder().decode(ZitiClaims.self, from: json.data(using: .utf8)!)
52+
53+
XCTAssertEqual(decoded.sub, "identity-abc")
54+
XCTAssertEqual(decoded.iss, "https://ctrl:1280")
55+
XCTAssertEqual(decoded.em, "ott")
56+
XCTAssertEqual(decoded.exp, 9999999999)
57+
XCTAssertEqual(decoded.jti, "jti-xyz")
58+
}
59+
60+
func testDecodeMinimalJSON() throws {
61+
let json = """
62+
{"sub":"just-sub"}
63+
"""
64+
let decoded = try JSONDecoder().decode(ZitiClaims.self, from: json.data(using: .utf8)!)
65+
XCTAssertEqual(decoded.sub, "just-sub")
66+
XCTAssertNil(decoded.iss)
67+
XCTAssertNil(decoded.em)
68+
}
69+
}

0 commit comments

Comments
 (0)