Skip to content

Commit b74e002

Browse files
authored
Merge pull request spotify#212 from polac24/add-driver-tests
[SwiftDriverIntegraiton] Part IV: Add E2E tests for the swift driver integration #5
2 parents 9a34a99 + 811cc00 commit b74e002

File tree

4 files changed

+78
-36
lines changed

4 files changed

+78
-36
lines changed

Rakefile

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ DERIVED_DATA_DIR = File.join('.build').freeze
1010
RELEASES_ROOT_DIR = File.join('releases').freeze
1111

1212
EXECUTABLE_NAME = 'XCRemoteCache'
13-
EXECUTABLE_NAMES = ['xclibtool', 'xcpostbuild', 'xcprebuild', 'xcprepare', 'xcswiftc', 'xcld', 'xcldplusplus', 'xclipo']
13+
EXECUTABLE_NAMES = ['xclibtool', 'xcpostbuild', 'xcprebuild', 'xcprepare', 'xcswiftc', 'swiftc', 'xcswift-frontend', 'swift-frontend', 'xcld', 'xcldplusplus', 'xclipo']
1414
PROJECT_NAME = 'XCRemoteCache'
1515

1616
SWIFTLINT_ENABLED = true
@@ -59,6 +59,10 @@ task :build, [:configuration, :arch, :sdks, :is_archive] do |task, args|
5959

6060
# Path of the executable looks like: `.build/(debug|release)/XCRemoteCache`
6161
build_path_base = File.join(DERIVED_DATA_DIR, args.configuration)
62+
# swift-frontent integration requires that the SWIFT_EXEC is `swiftc` so create
63+
# a symbolic link between swiftc->xcswiftc and swift-frontend->xcswift-frontend
64+
system("cd #{build_path_base} && ln -s xcswiftc swiftc")
65+
system("cd #{build_path_base} && ln -s xcswift-frontend swift-frontend")
6266
sdk_build_paths = EXECUTABLE_NAMES.map {|e| File.join(build_path_base, e)}
6367

6468
build_paths.push(sdk_build_paths)
@@ -130,7 +134,9 @@ def create_release_zip(build_paths)
130134
# Create and move files into the release directory
131135
mkdir_p release_dir
132136
build_paths.each {|p|
133-
cp_r p, release_dir
137+
# -r for recursive
138+
# -P for copying symbolic link as is
139+
system("cp -rP #{p} #{release_dir}")
134140
}
135141

136142
output_artifact_basename = "#{PROJECT_NAME}.zip"
@@ -139,7 +145,8 @@ def create_release_zip(build_paths)
139145
# -X: no extras (uid, gid, file times, ...)
140146
# -x: exclude .DS_Store
141147
# -r: recursive
142-
system("zip -X -x '*.DS_Store' -r #{output_artifact_basename} .") or abort "zip failure"
148+
# -y: to store symbolic links (used for swiftc -> xcswiftc)
149+
system("zip -X -x '*.DS_Store' -r -y #{output_artifact_basename} .") or abort "zip failure"
143150
# List contents of zip file
144151
system("unzip -l #{output_artifact_basename}") or abort "unzip failure"
145152
end

cocoapods-plugin/lib/cocoapods-xcremotecache/command/hooks.rb

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ def self.enable_xcremotecache(
123123
exclude_build_configurations,
124124
final_target,
125125
fake_src_root,
126-
exclude_sdks_configurations
126+
exclude_sdks_configurations,
127+
enable_swift_driver_integration
127128
)
128129
srcroot_relative_xc_location = parent_dir(xc_location, repo_distance)
129130
# location of the entrite CocoaPods project, relative to SRCROOT
@@ -137,14 +138,15 @@ def self.enable_xcremotecache(
137138
elsif mode == 'producer' || mode == 'producer-fast'
138139
config.build_settings.delete('CC') if config.build_settings.key?('CC')
139140
end
140-
reset_build_setting(config.build_settings, 'SWIFT_EXEC', "$SRCROOT/#{srcroot_relative_xc_location}/xcswiftc", exclude_sdks_configurations)
141+
swiftc_name = enable_swift_driver_integration ? 'swiftc' : 'xcswiftc'
142+
reset_build_setting(config.build_settings, 'SWIFT_EXEC', "$SRCROOT/#{srcroot_relative_xc_location}/#{swiftc_name}", exclude_sdks_configurations)
141143
reset_build_setting(config.build_settings, 'LIBTOOL', "$SRCROOT/#{srcroot_relative_xc_location}/xclibtool", exclude_sdks_configurations)
142144
# Setting LIBTOOL to '' breaks SwiftDriver intengration so resetting it to the original value 'libtool' for all excluded configurations
143145
add_build_setting_for_sdks(config.build_settings, 'LIBTOOL', 'libtool', exclude_sdks_configurations)
144146
reset_build_setting(config.build_settings, 'LD', "$SRCROOT/#{srcroot_relative_xc_location}/xcld", exclude_sdks_configurations)
145147
reset_build_setting(config.build_settings, 'LDPLUSPLUS', "$SRCROOT/#{srcroot_relative_xc_location}/xcldplusplus", exclude_sdks_configurations)
146148
reset_build_setting(config.build_settings, 'LIPO', "$SRCROOT/#{srcroot_relative_xc_location}/xclipo", exclude_sdks_configurations)
147-
reset_build_setting(config.build_settings, 'SWIFT_USE_INTEGRATED_DRIVER', 'NO', exclude_sdks_configurations)
149+
reset_build_setting(config.build_settings, 'SWIFT_USE_INTEGRATED_DRIVER', 'NO', exclude_sdks_configurations) unless enable_swift_driver_integration
148150

149151
reset_build_setting(config.build_settings, 'XCREMOTE_CACHE_FAKE_SRCROOT', fake_src_root, exclude_sdks_configurations)
150152
reset_build_setting(config.build_settings, 'XCRC_PLATFORM_PREFERRED_ARCH', "$(LINK_FILE_LIST_$(CURRENT_VARIANT)_$(PLATFORM_PREFERRED_ARCH):dir:standardizepath:file:default=arm64)", exclude_sdks_configurations)
@@ -498,6 +500,7 @@ def self.save_lldbinit_rewrite(user_proj_directory,fake_src_root)
498500
check_platform = @@configuration['check_platform']
499501
fake_src_root = @@configuration['fake_src_root']
500502
exclude_sdks_configurations = @@configuration['exclude_sdks_configurations'] || []
503+
enable_swift_driver_integration = @@configuration['enable_swift_driver_integration'] || false
501504

502505
xccc_location_absolute = "#{user_proj_directory}/#{xccc_location}"
503506
xcrc_location_absolute = "#{user_proj_directory}/#{xcrc_location}"
@@ -521,7 +524,7 @@ def self.save_lldbinit_rewrite(user_proj_directory,fake_src_root)
521524
next if target.name.start_with?("Pods-")
522525
next if target.name.end_with?("Tests")
523526
next if exclude_targets.include?(target.name)
524-
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations)
527+
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations, enable_swift_driver_integration)
525528
end
526529

527530
# Create .rcinfo into `Pods` directory as that .xcodeproj reads configuration from .xcodeproj location
@@ -534,7 +537,7 @@ def self.save_lldbinit_rewrite(user_proj_directory,fake_src_root)
534537
next if target.source_build_phase.files_references.empty?
535538
next if target.name.end_with?("Tests")
536539
next if exclude_targets.include?(target.name)
537-
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations)
540+
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations, enable_swift_driver_integration)
538541
end
539542
generated_project.save()
540543
end
@@ -575,7 +578,7 @@ def self.save_lldbinit_rewrite(user_proj_directory,fake_src_root)
575578
# Attach XCRC to the app targets
576579
user_project.targets.each do |target|
577580
next if exclude_targets.include?(target.name)
578-
enable_xcremotecache(target, 0, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations)
581+
enable_xcremotecache(target, 0, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root, exclude_sdks_configurations, enable_swift_driver_integration)
579582
end
580583

581584
# Set Target sourcemap

cocoapods-plugin/lib/cocoapods-xcremotecache/gem_version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@
1313
# limitations under the License.
1414

1515
module CocoapodsXcremotecache
16-
VERSION = "0.0.16"
16+
VERSION = "0.0.17"
1717
end

tasks/e2e.rb

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'json'
22
require "ostruct"
3+
require 'yaml'
34

45
desc 'Support for E2E tests: building XCRemoteCache-enabled xcodeproj using xcodebuild'
56
namespace :e2e do
@@ -25,12 +26,21 @@
2526
'primary_branch' => GIT_BRANCH,
2627
'mode' => 'consumer',
2728
'final_target' => 'XCRemoteCacheSample',
28-
'artifact_maximum_age' => 0
29+
'artifact_maximum_age' => 0,
30+
31+
}.freeze
32+
# A list of configurations to merge with SHARED_COCOAPODS_CONFIG to run tests with
33+
CONFIGS = {
34+
'no_swift_driver' => {},
35+
'swift_driver' => {
36+
'enable_swift_driver_integration' => true
37+
}
2938
}.freeze
3039
DEFAULT_EXPECTATIONS = {
3140
'misses' => 0,
3241
'hit_rate' => 100
3342
}.freeze
43+
EXCLUDED_ARCHS = 'x86_64'
3444

3545
Stats = Struct.new(:hits, :misses, :hit_rate)
3646

@@ -43,9 +53,14 @@
4353
start_nginx
4454
configure_git
4555

46-
# Run scenarios for all Podfile scenarios
47-
for podfile_path in Dir.glob('e2eTests/**/*.Podfile')
48-
run_cocoapods_scenario(podfile_path)
56+
for config_name, custom_config in CONFIGS
57+
config = SHARED_COCOAPODS_CONFIG.merge(custom_config)
58+
puts "Running E2E tests for config: #{config_name}"
59+
60+
# Run scenarios for all Podfile scenarios
61+
for podfile_path in Dir.glob('e2eTests/**/*.Podfile')
62+
run_cocoapods_scenario(config, podfile_path)
63+
end
4964
end
5065
# Revert all side effects
5166
clean
@@ -56,13 +71,27 @@
5671
clean_server
5772
start_nginx
5873
configure_git
74+
CONFIGS.each do |config_name, config|
75+
puts "Running Standalone tests for config: #{config_name}"
76+
run_standalone_scenario(config, config_name)
77+
end
78+
end
79+
80+
def self.run_standalone_scenario(config, config_name)
5981
# Prepare binaries for the standalone mode
6082
prepare_for_standalone(E2E_STANDALONE_SAMPLE_DIR)
6183

6284
puts 'Building standalone producer...'
6385
####### Producer #########
86+
clean_git
87+
6488
Dir.chdir(E2E_STANDALONE_SAMPLE_DIR) do
65-
clean_git
89+
system 'git checkout -f .'
90+
# Include the config in the "shared" configuration that is commited-in to '.rcinfo'
91+
rcinfo_path = '.rcinfo'
92+
rcinfo = YAML.load(File.read(rcinfo_path)).merge(config)
93+
File.open(rcinfo_path, 'w') {|f| f.write rcinfo.to_yaml }
94+
6695
# Run integrate the project
6796
system("pwd")
6897
system("#{XCRC_BINARIES}/xcprepare integrate --input StandaloneApp.xcodeproj --mode producer --final-producer-target StandaloneApp --configurations-exclude #{CONFIGURATIONS_EXCLUDE}")
@@ -76,22 +105,25 @@
76105

77106
####### Consumer #########
78107
# new dir to emulate different srcroot
79-
consumer_srcroot = "#{E2E_STANDALONE_SAMPLE_DIR}_consumer"
108+
consumer_srcroot = "#{E2E_STANDALONE_SAMPLE_DIR}_consumer_#{config_name}"
80109
system("mv #{E2E_STANDALONE_SAMPLE_DIR} #{consumer_srcroot}")
81-
at_exit { puts("reverting #{E2E_STANDALONE_SAMPLE_DIR}"); system("mv #{consumer_srcroot} #{E2E_STANDALONE_SAMPLE_DIR}") }
82-
83-
prepare_for_standalone(consumer_srcroot)
84-
Dir.chdir(consumer_srcroot) do
85-
system("#{XCRC_BINARIES}/xcprepare integrate --input StandaloneApp.xcodeproj --mode consumer --final-producer-target StandaloneApp --consumer-eligible-configurations #{CONFIGURATION} --configurations-exclude #{CONFIGURATIONS_EXCLUDE}")
86-
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer"})
87-
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp', 'iphone', 'iOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer"})
88-
valide_hit_rate(OpenStruct.new(DEFAULT_EXPECTATIONS))
89-
90-
puts 'Building standalone consumer with local change...'
91-
# Extra: validate local compilation of the Standalone ObjC code
92-
system("echo '' >> StandaloneApp/StandaloneObjc.m")
93-
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local"})
94-
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp', 'iphone', 'iOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local"})
110+
begin
111+
prepare_for_standalone(consumer_srcroot)
112+
Dir.chdir(consumer_srcroot) do
113+
system("#{XCRC_BINARIES}/xcprepare integrate --input StandaloneApp.xcodeproj --mode consumer --final-producer-target StandaloneApp --consumer-eligible-configurations #{CONFIGURATION} --configurations-exclude #{CONFIGURATIONS_EXCLUDE}")
114+
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_#{config_name}"})
115+
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp', 'iphone', 'iOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_#{config_name}"})
116+
valide_hit_rate(OpenStruct.new(DEFAULT_EXPECTATIONS))
117+
118+
puts 'Building standalone consumer with local change...'
119+
# Extra: validate local compilation of the Standalone ObjC code
120+
system("echo '' >> StandaloneApp/StandaloneObjc.m")
121+
build_project(nil, "StandaloneApp.xcodeproj", 'WatchExtension', 'watch', 'watchOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local_#{config_name}"})
122+
build_project(nil, "StandaloneApp.xcodeproj", 'StandaloneApp', 'iphone', 'iOS', CONFIGURATION, {'derivedDataPath' => "#{DERIVED_DATA_PATH}_consumer_local_#{config_name}"})
123+
end
124+
ensure
125+
puts("reverting #{E2E_STANDALONE_SAMPLE_DIR}")
126+
system("mv #{consumer_srcroot} #{E2E_STANDALONE_SAMPLE_DIR}")
95127
end
96128

97129
# Revert all side effects
@@ -153,9 +185,9 @@ def self.clean
153185
end
154186

155187
# xcremotecache configuration to add to Podfile
156-
def self.cocoapods_configuration_string(extra_configs = {})
188+
def self.cocoapods_configuration_string(config, extra_configs = {})
157189
configuration_lines = ['xcremotecache({']
158-
all_properties = SHARED_COCOAPODS_CONFIG.merge(extra_configs)
190+
all_properties = config.merge(extra_configs)
159191
config_lines = all_properties.map {|key, value| " \"#{key}\" => #{value.inspect},"}
160192
configuration_lines.push(*config_lines)
161193
configuration_lines << '})'
@@ -182,7 +214,7 @@ def self.build_project(workspace, project, scheme, sdk = 'iphone', platform = 'i
182214
'derivedDataPath' => DERIVED_DATA_PATH,
183215
}.merge(extra_args).compact
184216
xcodebuild_vars = {
185-
'EXCLUDED_ARCHS' => 'arm64'
217+
'EXCLUDED_ARCHS' => EXCLUDED_ARCHS
186218
}
187219
args = ['set -o pipefail;', 'xcodebuild']
188220
args.push(*xcodebuild_args.map {|k,v| "-#{k} '#{v}'"})
@@ -227,12 +259,12 @@ def self.valide_hit_rate(expectations)
227259
puts("Hit rate: #{status.hit_rate}% (#{status.hits}/#{all_targets})")
228260
end
229261

230-
def self.run_cocoapods_scenario(template_path)
262+
def self.run_cocoapods_scenario(config, template_path)
231263
# Optional file, which adds extra cocoapods configs to a template
232264
template_config_path = "#{template_path}.config"
233265
extra_config = File.exist?(template_config_path) ? JSON.load(File.read(template_config_path)) : {}
234-
producer_configuration = cocoapods_configuration_string({'mode' => 'producer'}.merge(extra_config))
235-
consumer_configuration = cocoapods_configuration_string(extra_config)
266+
producer_configuration = cocoapods_configuration_string(config, {'mode' => 'producer'}.merge(extra_config))
267+
consumer_configuration = cocoapods_configuration_string(config, extra_config)
236268
expectations = build_expectations(template_path)
237269

238270
puts("****** Scenario: #{template_path}")

0 commit comments

Comments
 (0)