Skip to content

Commit 0014c47

Browse files
committed
Use semaphore to serialize test execution
1 parent 1cc3217 commit 0014c47

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

IdentityCore/tests/MSIDWorkPlaceJoinUtilTests.m

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2222
// THE SOFTWARE.
2323

24+
#include <semaphore.h>
25+
2426
#import <XCTest/XCTest.h>
2527
#import "MSIDKeychainUtil.h"
2628
#import "MSIDWorkPlaceJoinUtil.h"
@@ -70,6 +72,8 @@ - (void)setUp
7072
#if TARGET_OS_OSX
7173
self.useIosStyleKeychain = NO;
7274
#endif
75+
[self.class initialize];
76+
[self.class acquireGlobalWPJTestLockWithTimeout:2.0];
7377
}
7478

7579
- (void)tearDown
@@ -79,6 +83,7 @@ - (void)tearDown
7983
[self cleanWPJ:[self keychainGroup:YES]];
8084
[self cleanWPJ:[self keychainGroup:NO]];
8185
}
86+
[self.class releaseGlobalWPJTestLock];
8287
[MSIDTestSwizzle reset];
8388
}
8489

@@ -893,5 +898,64 @@ - (void)insertEccStkKeyForTenantIdentifier:(NSString *)tenantIdentifier
893898
privateKeyTag:stkTag
894899
accessGroup:keychainGroup];
895900
}
901+
# pragma mark -- Serial execution of tests
902+
903+
// Global interprocess semaphore (named; no file fallback)
904+
static sem_t *s_wpjNamedSem = SEM_FAILED;
905+
906+
+ (void)initialize
907+
{
908+
if (self != [MSIDWorkPlaceJoinUtilTests class]) return;
909+
910+
static dispatch_once_t onceToken;
911+
dispatch_once(&onceToken, ^{
912+
// Named POSIX semaphore (not file-based). Name must start with '/'.
913+
s_wpjNamedSem = sem_open("/com.microsoft.msid.wpj.tests.sem", O_CREAT, 0666, 1);
914+
});
915+
}
916+
917+
+ (BOOL)acquireGlobalWPJTestLockWithTimeout:(NSTimeInterval)timeoutSec
918+
{
919+
if (s_wpjNamedSem == SEM_FAILED) return NO;
920+
921+
// Blocking acquire if timeout is negative
922+
if (timeoutSec < 0) {
923+
int rc;
924+
do { rc = sem_wait(s_wpjNamedSem); } while (rc == -1 && errno == EINTR);
925+
return rc == 0;
926+
}
927+
928+
// Immediate try if timeout is zero
929+
if (timeoutSec == 0) {
930+
int rc;
931+
do { rc = sem_trywait(s_wpjNamedSem); } while (rc == -1 && errno == EINTR);
932+
return rc == 0;
933+
}
934+
935+
CFAbsoluteTime deadline = CFAbsoluteTimeGetCurrent() + timeoutSec;
936+
struct timespec sleepTs = { .tv_sec = 0, .tv_nsec = 10 * 1000 * 1000 }; // 10ms
937+
938+
for (;;) {
939+
int rc = sem_trywait(s_wpjNamedSem);
940+
if (rc == 0) return YES;
941+
942+
if (errno != EAGAIN && errno != EINTR) {
943+
return NO; // unexpected error
944+
}
945+
946+
if (CFAbsoluteTimeGetCurrent() >= deadline) {
947+
return NO; // timed out
948+
}
949+
950+
nanosleep(&sleepTs, NULL);
951+
}
952+
}
953+
954+
+ (void)releaseGlobalWPJTestLock
955+
{
956+
if (s_wpjNamedSem != SEM_FAILED) {
957+
sem_post(s_wpjNamedSem);
958+
}
959+
}
896960

897961
@end

0 commit comments

Comments
 (0)