/*
* Copyright 2015-present Facebook, Inc.
*
* 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.
*/
package com.facebook.buck.apple;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import com.dd.plist.NSDictionary;
import com.dd.plist.NSObject;
import com.dd.plist.NSString;
import com.dd.plist.PropertyListParser;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.step.TestExecutionContext;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.facebook.buck.testutil.TestConsole;
import com.facebook.buck.testutil.integration.TemporaryPaths;
import com.facebook.buck.testutil.integration.TestDataHelper;
import com.facebook.buck.util.DefaultProcessExecutor;
import com.facebook.buck.util.HumanReadableException;
import com.facebook.buck.util.environment.Platform;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Optional;
import java.util.concurrent.Future;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class ProvisioningProfileCopyStepTest {
private Path testdataDir;
private Path tempOutputDir;
private Path outputFile;
private Path xcentFile;
private Path dryRunResultFile;
private Path entitlementsFile;
private ProjectFilesystem projectFilesystem;
private ExecutionContext executionContext;
private CodeSignIdentityStore codeSignIdentityStore;
private static final ImmutableList<String> FAKE_READ_COMMAND = ImmutableList.of("cat");
@Rule public ExpectedException thrown = ExpectedException.none();
@Rule public final TemporaryPaths tmp = new TemporaryPaths();
@Before
public void setUp() throws IOException {
testdataDir = TestDataHelper.getTestDataDirectory(this).resolve("provisioning_profiles");
projectFilesystem = new FakeProjectFilesystem(testdataDir);
Files.walkFileTree(
testdataDir,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
projectFilesystem.writeBytesToPath(
Files.readAllBytes(file), projectFilesystem.resolve(file));
return FileVisitResult.CONTINUE;
}
});
tempOutputDir = tmp.getRoot();
outputFile = tempOutputDir.resolve("embedded.mobileprovision");
xcentFile = Paths.get("test.xcent");
dryRunResultFile = Paths.get("test_dry_run_results.plist");
executionContext = TestExecutionContext.newInstance();
codeSignIdentityStore = CodeSignIdentityStore.fromIdentities(ImmutableList.of());
entitlementsFile = testdataDir.resolve("Entitlements.plist");
}
@Test
public void testFailsWithInvalidEntitlementsPlist() throws Exception {
assumeTrue(Platform.detect() == Platform.MACOS);
thrown.expect(HumanReadableException.class);
thrown.expectMessage(startsWith("Malformed entitlement .plist: "));
ProvisioningProfileCopyStep step =
new ProvisioningProfileCopyStep(
projectFilesystem,
testdataDir.resolve("Info.plist"),
ApplePlatform.IPHONEOS,
Optional.empty(),
Optional.of(testdataDir.resolve("Invalid.plist")),
ProvisioningProfileStore.fromSearchPath(
new DefaultProcessExecutor(new TestConsole()), FAKE_READ_COMMAND, testdataDir),
outputFile,
xcentFile,
codeSignIdentityStore,
Optional.empty());
step.execute(executionContext);
}
@Test
public void testFailsWithInvalidInfoPlist() throws Exception {
assumeTrue(Platform.detect() == Platform.MACOS);
thrown.expect(HumanReadableException.class);
thrown.expectMessage(startsWith("Unable to get bundle ID from info.plist"));
ProvisioningProfileCopyStep step =
new ProvisioningProfileCopyStep(
projectFilesystem,
testdataDir.resolve("Invalid.plist"),
ApplePlatform.IPHONEOS,
Optional.empty(),
Optional.empty(),
ProvisioningProfileStore.fromSearchPath(
new DefaultProcessExecutor(new TestConsole()), FAKE_READ_COMMAND, testdataDir),
outputFile,
xcentFile,
codeSignIdentityStore,
Optional.empty());
step.execute(executionContext);
}
@Test
public void testFailsWithNoSuitableProfilesFound() throws Exception {
assumeTrue(Platform.detect() == Platform.MACOS);
thrown.expect(HumanReadableException.class);
thrown.expectMessage(
"No valid non-expired provisioning profiles match for *.com.example.TestApp");
Path emptyDir =
TestDataHelper.getTestDataDirectory(this).resolve("provisioning_profiles_empty");
ProvisioningProfileCopyStep step =
new ProvisioningProfileCopyStep(
projectFilesystem,
testdataDir.resolve("Info.plist"),
ApplePlatform.IPHONEOS,
Optional.empty(),
Optional.empty(),
ProvisioningProfileStore.fromSearchPath(
new DefaultProcessExecutor(new TestConsole()), FAKE_READ_COMMAND, emptyDir),
outputFile,
xcentFile,
codeSignIdentityStore,
Optional.empty());
step.execute(executionContext);
}
@Test
public void testDoesNotFailInDryRunMode() throws Exception {
assumeTrue(Platform.detect() == Platform.MACOS);
Path emptyDir =
TestDataHelper.getTestDataDirectory(this).resolve("provisioning_profiles_empty");
ProvisioningProfileCopyStep step =
new ProvisioningProfileCopyStep(
projectFilesystem,
testdataDir.resolve("Info.plist"),
ApplePlatform.IPHONEOS,
Optional.empty(),
Optional.empty(),
ProvisioningProfileStore.fromSearchPath(
new DefaultProcessExecutor(new TestConsole()), FAKE_READ_COMMAND, emptyDir),
outputFile,
xcentFile,
codeSignIdentityStore,
Optional.of(dryRunResultFile));
Future<Optional<ProvisioningProfileMetadata>> profileFuture =
step.getSelectedProvisioningProfileFuture();
step.execute(executionContext);
assertTrue(profileFuture.isDone());
assertNotNull(profileFuture.get());
assertFalse(profileFuture.get().isPresent());
Optional<String> resultContents = projectFilesystem.readFileIfItExists(dryRunResultFile);
assertTrue(resultContents.isPresent());
NSDictionary resultPlist =
(NSDictionary) PropertyListParser.parse(resultContents.get().getBytes(Charsets.UTF_8));
assertEquals(new NSString("com.example.TestApp"), resultPlist.get("bundle-id"));
}
@Test
public void shouldSetProvisioningProfileFutureWhenStepIsRun() throws Exception {
assumeTrue(Platform.detect() == Platform.MACOS);
ProvisioningProfileCopyStep step =
new ProvisioningProfileCopyStep(
projectFilesystem,
testdataDir.resolve("Info.plist"),
ApplePlatform.IPHONEOS,
Optional.empty(),
Optional.empty(),
ProvisioningProfileStore.fromSearchPath(
new DefaultProcessExecutor(new TestConsole()), FAKE_READ_COMMAND, testdataDir),
outputFile,
xcentFile,
codeSignIdentityStore,
Optional.empty());
Future<Optional<ProvisioningProfileMetadata>> profileFuture =
step.getSelectedProvisioningProfileFuture();
step.execute(executionContext);
assertTrue(profileFuture.isDone());
assertNotNull(profileFuture.get());
}
@Test
public void testNoEntitlementsDoesNotMergeInvalidProfileKeys() throws Exception {
assumeTrue(Platform.detect() == Platform.MACOS);
ProvisioningProfileCopyStep step =
new ProvisioningProfileCopyStep(
projectFilesystem,
testdataDir.resolve("Info.plist"),
ApplePlatform.IPHONEOS,
Optional.of("00000000-0000-0000-0000-000000000000"),
Optional.empty(),
ProvisioningProfileStore.fromSearchPath(
new DefaultProcessExecutor(new TestConsole()), FAKE_READ_COMMAND, testdataDir),
outputFile,
xcentFile,
codeSignIdentityStore,
Optional.empty());
step.execute(executionContext);
ProvisioningProfileMetadata selectedProfile =
step.getSelectedProvisioningProfileFuture().get().get();
ImmutableMap<String, NSObject> profileEntitlements = selectedProfile.getEntitlements();
assertTrue(
profileEntitlements.containsKey(
"com.apple.developer.icloud-container-development-container-identifiers"));
Optional<String> xcentContents = projectFilesystem.readFileIfItExists(xcentFile);
assertTrue(xcentContents.isPresent());
NSDictionary xcentPlist =
(NSDictionary) PropertyListParser.parse(xcentContents.get().getBytes());
assertFalse(
xcentPlist.containsKey(
"com.apple.developer.icloud-container-development-container-identifiers"));
assertEquals(
xcentPlist.get("com.apple.developer.team-identifier"),
profileEntitlements.get("com.apple.developer.team-identifier"));
}
@Test
public void testEntitlementsDoesNotMergeInvalidProfileKeys() throws Exception {
assumeTrue(Platform.detect() == Platform.MACOS);
ProvisioningProfileCopyStep step =
new ProvisioningProfileCopyStep(
projectFilesystem,
testdataDir.resolve("Info.plist"),
ApplePlatform.IPHONEOS,
Optional.of("00000000-0000-0000-0000-000000000000"),
Optional.of(entitlementsFile),
ProvisioningProfileStore.fromSearchPath(
new DefaultProcessExecutor(new TestConsole()), FAKE_READ_COMMAND, testdataDir),
outputFile,
xcentFile,
codeSignIdentityStore,
Optional.empty());
step.execute(executionContext);
ProvisioningProfileMetadata selectedProfile =
step.getSelectedProvisioningProfileFuture().get().get();
ImmutableMap<String, NSObject> profileEntitlements = selectedProfile.getEntitlements();
assertTrue(
profileEntitlements.containsKey(
"com.apple.developer.icloud-container-development-container-identifiers"));
Optional<String> xcentContents = projectFilesystem.readFileIfItExists(xcentFile);
assertTrue(xcentContents.isPresent());
NSDictionary xcentPlist =
(NSDictionary) PropertyListParser.parse(xcentContents.get().getBytes());
assertFalse(
xcentPlist.containsKey(
"com.apple.developer.icloud-container-development-container-identifiers"));
assertEquals(
xcentPlist.get("com.apple.developer.team-identifier"),
profileEntitlements.get("com.apple.developer.team-identifier"));
}
}