Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67bfa9f681 | ||
|
|
4973a67ca9 |
@@ -9,6 +9,7 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
160334CC765E091A7CBE21AA /* MMCPULoadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE92B1A8D7FDBB6499448E1 /* MMCPULoadTests.swift */; };
|
160334CC765E091A7CBE21AA /* MMCPULoadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE92B1A8D7FDBB6499448E1 /* MMCPULoadTests.swift */; };
|
||||||
1879A3DCF6E305D7F2CD472E /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2345555FF9780B02A90CC7A9 /* CoreFoundation.framework */; };
|
1879A3DCF6E305D7F2CD472E /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2345555FF9780B02A90CC7A9 /* CoreFoundation.framework */; };
|
||||||
|
1B15F48F6B19E9EA4556ECD5 /* MMStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78325870C7CD8312AECA2236 /* MMStorageTests.swift */; };
|
||||||
1B3F1C8ABF0ADFAA290FF6F6 /* MMSMCParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 375AA781A2AA0A20B119C7B7 /* MMSMCParser.m */; };
|
1B3F1C8ABF0ADFAA290FF6F6 /* MMSMCParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 375AA781A2AA0A20B119C7B7 /* MMSMCParser.m */; };
|
||||||
3C0AC14F803C813287D8A663 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 007F48A5A599AB4E8D216D16 /* IOKit.framework */; };
|
3C0AC14F803C813287D8A663 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 007F48A5A599AB4E8D216D16 /* IOKit.framework */; };
|
||||||
4419FE7554489B23976E2970 /* MMCPULoadProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = D68FC8100D08DB6202F46339 /* MMCPULoadProvider.m */; };
|
4419FE7554489B23976E2970 /* MMCPULoadProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = D68FC8100D08DB6202F46339 /* MMCPULoadProvider.m */; };
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
CD91FC663B19DA1FEA3D49D7 /* MMAppleSMCClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 5555436CD3CB8A73F5D6504F /* MMAppleSMCClient.m */; };
|
CD91FC663B19DA1FEA3D49D7 /* MMAppleSMCClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 5555436CD3CB8A73F5D6504F /* MMAppleSMCClient.m */; };
|
||||||
EAFAF5A10502D4ACC64F4720 /* MMTelemetryCoordinator.m in Sources */ = {isa = PBXBuildFile; fileRef = F9F9AD1268F906761032AF4D /* MMTelemetryCoordinator.m */; };
|
EAFAF5A10502D4ACC64F4720 /* MMTelemetryCoordinator.m in Sources */ = {isa = PBXBuildFile; fileRef = F9F9AD1268F906761032AF4D /* MMTelemetryCoordinator.m */; };
|
||||||
EC9FA3E4A119277B89E73F8D /* MMSMCTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 940D608A1AF80F75584E744E /* MMSMCTests.swift */; };
|
EC9FA3E4A119277B89E73F8D /* MMSMCTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 940D608A1AF80F75584E744E /* MMSMCTests.swift */; };
|
||||||
|
F2F7A141F2452EC1B4FB45D8 /* MMStorageTelemetryProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DCBCEA450103E2404761B78 /* MMStorageTelemetryProvider.m */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -42,13 +44,16 @@
|
|||||||
2EC3EDFCD5C50CB352FCED87 /* MacMonitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacMonitorTests.swift; sourceTree = "<group>"; };
|
2EC3EDFCD5C50CB352FCED87 /* MacMonitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacMonitorTests.swift; sourceTree = "<group>"; };
|
||||||
32340166F6100A08105308D3 /* MMTelemetryCoordinator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMTelemetryCoordinator.h; sourceTree = "<group>"; };
|
32340166F6100A08105308D3 /* MMTelemetryCoordinator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMTelemetryCoordinator.h; sourceTree = "<group>"; };
|
||||||
375AA781A2AA0A20B119C7B7 /* MMSMCParser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MMSMCParser.m; sourceTree = "<group>"; };
|
375AA781A2AA0A20B119C7B7 /* MMSMCParser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MMSMCParser.m; sourceTree = "<group>"; };
|
||||||
|
46DE3AE12DAE26C4FE58034C /* MMStorageTelemetryProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMStorageTelemetryProvider.h; sourceTree = "<group>"; };
|
||||||
4CE92B1A8D7FDBB6499448E1 /* MMCPULoadTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MMCPULoadTests.swift; sourceTree = "<group>"; };
|
4CE92B1A8D7FDBB6499448E1 /* MMCPULoadTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MMCPULoadTests.swift; sourceTree = "<group>"; };
|
||||||
5555436CD3CB8A73F5D6504F /* MMAppleSMCClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MMAppleSMCClient.m; sourceTree = "<group>"; };
|
5555436CD3CB8A73F5D6504F /* MMAppleSMCClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MMAppleSMCClient.m; sourceTree = "<group>"; };
|
||||||
5635101F862DE680856BDE6E /* MMTelemetryDomain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMTelemetryDomain.h; sourceTree = "<group>"; };
|
5635101F862DE680856BDE6E /* MMTelemetryDomain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMTelemetryDomain.h; sourceTree = "<group>"; };
|
||||||
56E285A0A1746AE659981F22 /* MacMonitorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MacMonitorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
56E285A0A1746AE659981F22 /* MacMonitorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MacMonitorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
57845310A3D4EC67E48A3B11 /* MMCPULoadProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMCPULoadProvider.h; sourceTree = "<group>"; };
|
57845310A3D4EC67E48A3B11 /* MMCPULoadProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMCPULoadProvider.h; sourceTree = "<group>"; };
|
||||||
6D0E5CAF25DFA9A1D2A698A0 /* MMTelemetryProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMTelemetryProvider.h; sourceTree = "<group>"; };
|
6D0E5CAF25DFA9A1D2A698A0 /* MMTelemetryProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMTelemetryProvider.h; sourceTree = "<group>"; };
|
||||||
|
6DCBCEA450103E2404761B78 /* MMStorageTelemetryProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MMStorageTelemetryProvider.m; sourceTree = "<group>"; };
|
||||||
726005CB5A6C86E7D80D3CA0 /* MMAppleSMCClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMAppleSMCClient.h; sourceTree = "<group>"; };
|
726005CB5A6C86E7D80D3CA0 /* MMAppleSMCClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMAppleSMCClient.h; sourceTree = "<group>"; };
|
||||||
|
78325870C7CD8312AECA2236 /* MMStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MMStorageTests.swift; sourceTree = "<group>"; };
|
||||||
8FBB436F3D9472194D8C6EDD /* MMSMCDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMSMCDefines.h; sourceTree = "<group>"; };
|
8FBB436F3D9472194D8C6EDD /* MMSMCDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMSMCDefines.h; sourceTree = "<group>"; };
|
||||||
940D608A1AF80F75584E744E /* MMSMCTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MMSMCTests.swift; sourceTree = "<group>"; };
|
940D608A1AF80F75584E744E /* MMSMCTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MMSMCTests.swift; sourceTree = "<group>"; };
|
||||||
991AEEAF262F3C6BE930BC77 /* MMMemoryTelemetryProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MMMemoryTelemetryProvider.m; sourceTree = "<group>"; };
|
991AEEAF262F3C6BE930BC77 /* MMMemoryTelemetryProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MMMemoryTelemetryProvider.m; sourceTree = "<group>"; };
|
||||||
@@ -137,6 +142,7 @@
|
|||||||
children = (
|
children = (
|
||||||
78383CED205BCA772701AE48 /* CPU */,
|
78383CED205BCA772701AE48 /* CPU */,
|
||||||
EE2F5EFC9DC33CEDA79A131F /* Memory */,
|
EE2F5EFC9DC33CEDA79A131F /* Memory */,
|
||||||
|
B6EB3F6545276C40212C2992 /* Storage */,
|
||||||
);
|
);
|
||||||
path = Telemetry;
|
path = Telemetry;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -149,6 +155,15 @@
|
|||||||
path = Hardware;
|
path = Hardware;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
B6EB3F6545276C40212C2992 /* Storage */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
46DE3AE12DAE26C4FE58034C /* MMStorageTelemetryProvider.h */,
|
||||||
|
6DCBCEA450103E2404761B78 /* MMStorageTelemetryProvider.m */,
|
||||||
|
);
|
||||||
|
path = Storage;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
C80C3EEE8F912F4B214102E3 /* Products */ = {
|
C80C3EEE8F912F4B214102E3 /* Products */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -165,6 +180,7 @@
|
|||||||
4CE92B1A8D7FDBB6499448E1 /* MMCPULoadTests.swift */,
|
4CE92B1A8D7FDBB6499448E1 /* MMCPULoadTests.swift */,
|
||||||
099DCF7EF03A58ADA40A94A1 /* MMMemoryTests.swift */,
|
099DCF7EF03A58ADA40A94A1 /* MMMemoryTests.swift */,
|
||||||
940D608A1AF80F75584E744E /* MMSMCTests.swift */,
|
940D608A1AF80F75584E744E /* MMSMCTests.swift */,
|
||||||
|
78325870C7CD8312AECA2236 /* MMStorageTests.swift */,
|
||||||
);
|
);
|
||||||
path = Tests;
|
path = Tests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -277,6 +293,7 @@
|
|||||||
160334CC765E091A7CBE21AA /* MMCPULoadTests.swift in Sources */,
|
160334CC765E091A7CBE21AA /* MMCPULoadTests.swift in Sources */,
|
||||||
6201FD599FED061F6C736E8B /* MMMemoryTests.swift in Sources */,
|
6201FD599FED061F6C736E8B /* MMMemoryTests.swift in Sources */,
|
||||||
EC9FA3E4A119277B89E73F8D /* MMSMCTests.swift in Sources */,
|
EC9FA3E4A119277B89E73F8D /* MMSMCTests.swift in Sources */,
|
||||||
|
1B15F48F6B19E9EA4556ECD5 /* MMStorageTests.swift in Sources */,
|
||||||
9BCE74C5454F81EF80492E75 /* MacMonitorTests.swift in Sources */,
|
9BCE74C5454F81EF80492E75 /* MacMonitorTests.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -290,6 +307,7 @@
|
|||||||
4419FE7554489B23976E2970 /* MMCPULoadProvider.m in Sources */,
|
4419FE7554489B23976E2970 /* MMCPULoadProvider.m in Sources */,
|
||||||
B9C2D6574E808B517BA34C83 /* MMMemoryTelemetryProvider.m in Sources */,
|
B9C2D6574E808B517BA34C83 /* MMMemoryTelemetryProvider.m in Sources */,
|
||||||
1B3F1C8ABF0ADFAA290FF6F6 /* MMSMCParser.m in Sources */,
|
1B3F1C8ABF0ADFAA290FF6F6 /* MMSMCParser.m in Sources */,
|
||||||
|
F2F7A141F2452EC1B4FB45D8 /* MMStorageTelemetryProvider.m in Sources */,
|
||||||
EAFAF5A10502D4ACC64F4720 /* MMTelemetryCoordinator.m in Sources */,
|
EAFAF5A10502D4ACC64F4720 /* MMTelemetryCoordinator.m in Sources */,
|
||||||
88387CDAE2AC1CC74EF89B57 /* MacMonitorApp.swift in Sources */,
|
88387CDAE2AC1CC74EF89B57 /* MacMonitorApp.swift in Sources */,
|
||||||
A7609CE56D49EC3419987468 /* SystemTelemetryStore.swift in Sources */,
|
A7609CE56D49EC3419987468 /* SystemTelemetryStore.swift in Sources */,
|
||||||
|
|||||||
@@ -14,5 +14,6 @@
|
|||||||
// Telemetry Providers
|
// Telemetry Providers
|
||||||
#import "MMCPULoadProvider.h"
|
#import "MMCPULoadProvider.h"
|
||||||
#import "MMMemoryTelemetryProvider.h"
|
#import "MMMemoryTelemetryProvider.h"
|
||||||
|
#import "MMStorageTelemetryProvider.h"
|
||||||
|
|
||||||
#endif /* MacMonitor_Bridging_Header_h */
|
#endif /* MacMonitor_Bridging_Header_h */
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef MMStorageTelemetryProvider_h
|
||||||
|
#define MMStorageTelemetryProvider_h
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <sys/mount.h>
|
||||||
|
#import "MMTelemetryProvider.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MMStorageTelemetryProvider
|
||||||
|
* Samples mounted disk volumes, APFS containers, used/free storage capacity,
|
||||||
|
* and mount filesystem attributes.
|
||||||
|
*/
|
||||||
|
@interface MMStorageTelemetryProvider : NSObject <MMTelemetryProvider>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static parser method for converting statfs structures into volume dictionaries.
|
||||||
|
*/
|
||||||
|
+ (NSArray<NSDictionary<NSString *, id> *> *)parseStatFSBuffer:(const struct statfs *)buffer count:(int)count;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
|
#endif /* MMStorageTelemetryProvider_h */
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#import "MMStorageTelemetryProvider.h"
|
||||||
|
|
||||||
|
@implementation MMStorageTelemetryProvider
|
||||||
|
|
||||||
|
- (MMTelemetryDomain)domain {
|
||||||
|
return MMTelemetryDomainStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)providerIdentifier {
|
||||||
|
return @"com.i3omb.macmonitor.telemetry.storage";
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isAvailable {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<NSDictionary<NSString *, id> *> *)parseStatFSBuffer:(const struct statfs *)buffer count:(int)count {
|
||||||
|
if (!buffer || count <= 0) return @[];
|
||||||
|
|
||||||
|
NSMutableArray<NSDictionary<NSString *, id> *> *volumes = [NSMutableArray arrayWithCapacity:count];
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
const struct statfs *mnt = &buffer[i];
|
||||||
|
|
||||||
|
// Only include local mounts
|
||||||
|
if (!(mnt->f_flags & MNT_LOCAL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *mountPoint = [NSString stringWithUTF8String:mnt->f_mntonname];
|
||||||
|
NSString *deviceName = [NSString stringWithUTF8String:mnt->f_mntfromname];
|
||||||
|
NSString *fsType = [NSString stringWithUTF8String:mnt->f_fstypename];
|
||||||
|
|
||||||
|
// Exclude virtual/internal devfs, autodefs, and synthetic system roots
|
||||||
|
if ([fsType isEqualToString:@"devfs"] ||
|
||||||
|
[fsType isEqualToString:@"autofs"] ||
|
||||||
|
[mountPoint hasPrefix:@"/System/Volumes/Data/"] ||
|
||||||
|
[deviceName containsString:@"com.apple.os.update"]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t blockSize = (uint64_t)mnt->f_bsize;
|
||||||
|
uint64_t totalBytes = (uint64_t)mnt->f_blocks * blockSize;
|
||||||
|
uint64_t freeBytes = (uint64_t)mnt->f_bfree * blockSize;
|
||||||
|
uint64_t availBytes = (uint64_t)mnt->f_bavail * blockSize;
|
||||||
|
uint64_t usedBytes = (totalBytes >= freeBytes) ? (totalBytes - freeBytes) : 0;
|
||||||
|
|
||||||
|
if (totalBytes == 0) continue;
|
||||||
|
|
||||||
|
double usedPercent = ((double)usedBytes / (double)totalBytes) * 100.0;
|
||||||
|
if (usedPercent < 0.0) usedPercent = 0.0;
|
||||||
|
if (usedPercent > 100.0) usedPercent = 100.0;
|
||||||
|
|
||||||
|
NSString *volumeName = [mountPoint lastPathComponent];
|
||||||
|
if ([mountPoint isEqualToString:@"/"]) {
|
||||||
|
volumeName = @"Macintosh HD";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL isReadOnly = (mnt->f_flags & MNT_RDONLY) != 0;
|
||||||
|
|
||||||
|
[volumes addObject:@{
|
||||||
|
@"volumeName": volumeName,
|
||||||
|
@"mountPoint": mountPoint,
|
||||||
|
@"devicePath": deviceName,
|
||||||
|
@"fsType": fsType,
|
||||||
|
@"totalBytes": @(totalBytes),
|
||||||
|
@"usedBytes": @(usedBytes),
|
||||||
|
@"freeBytes": @(freeBytes),
|
||||||
|
@"availableBytes": @(availBytes),
|
||||||
|
@"usedPercent": @(usedPercent),
|
||||||
|
@"isReadOnly": @(isReadOnly)
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [volumes copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSDictionary<NSString *, id> *)sampleTelemetryWithError:(NSError **)error {
|
||||||
|
struct statfs *mntbuf = NULL;
|
||||||
|
int count = getmntinfo(&mntbuf, MNT_WAIT);
|
||||||
|
|
||||||
|
if (count <= 0 || mntbuf == NULL) {
|
||||||
|
if (error) {
|
||||||
|
*error = [NSError errorWithDomain:@"com.i3omb.MacMonitor.Storage"
|
||||||
|
code:-1
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey: @"getmntinfo returned no mounted filesystems"}];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSArray *volumes = [MMStorageTelemetryProvider parseStatFSBuffer:mntbuf count:count];
|
||||||
|
|
||||||
|
uint64_t totalStorage = 0;
|
||||||
|
uint64_t totalUsed = 0;
|
||||||
|
for (NSDictionary *v in volumes) {
|
||||||
|
totalStorage += [v[@"totalBytes"] unsignedLongLongValue];
|
||||||
|
totalUsed += [v[@"usedBytes"] unsignedLongLongValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
return @{
|
||||||
|
@"volumes": volumes,
|
||||||
|
@"volumeCount": @(volumes.count),
|
||||||
|
@"aggregateTotalBytes": @(totalStorage),
|
||||||
|
@"aggregateUsedBytes": @(totalUsed)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import XCTest
|
||||||
|
@testable import MacMonitor
|
||||||
|
|
||||||
|
final class MMStorageTests: XCTestCase {
|
||||||
|
|
||||||
|
func testStatFSBufferParsing() {
|
||||||
|
var stat = statfs()
|
||||||
|
stat.f_bsize = 4096
|
||||||
|
stat.f_blocks = 125_000_000 // 500 GB
|
||||||
|
stat.f_bfree = 50_000_000 // 200 GB
|
||||||
|
stat.f_bavail = 45_000_000
|
||||||
|
stat.f_flags = UInt32(MNT_LOCAL)
|
||||||
|
|
||||||
|
let mountPath = "/Volumes/External"
|
||||||
|
let devicePath = "/dev/disk2s1"
|
||||||
|
let fsType = "apfs"
|
||||||
|
|
||||||
|
_ = mountPath.withCString { mntPtr in
|
||||||
|
strncpy(&stat.f_mntonname.0, mntPtr, Int(MNAMELEN))
|
||||||
|
}
|
||||||
|
_ = devicePath.withCString { devPtr in
|
||||||
|
strncpy(&stat.f_mntfromname.0, devPtr, Int(MNAMELEN))
|
||||||
|
}
|
||||||
|
_ = fsType.withCString { fsPtr in
|
||||||
|
strncpy(&stat.f_fstypename.0, fsPtr, Int(MFSTYPENAMELEN))
|
||||||
|
}
|
||||||
|
|
||||||
|
withUnsafePointer(to: stat) { ptr in
|
||||||
|
let volumes = MMStorageTelemetryProvider.parseStatFSBuffer(ptr, count: 1)
|
||||||
|
XCTAssertEqual(volumes.count, 1)
|
||||||
|
|
||||||
|
let vol = volumes.first!
|
||||||
|
XCTAssertEqual(vol["volumeName"] as? String, "External")
|
||||||
|
XCTAssertEqual(vol["mountPoint"] as? String, "/Volumes/External")
|
||||||
|
XCTAssertEqual(vol["devicePath"] as? String, "/dev/disk2s1")
|
||||||
|
XCTAssertEqual(vol["fsType"] as? String, "apfs")
|
||||||
|
|
||||||
|
let total = vol["totalBytes"] as? UInt64 ?? 0
|
||||||
|
let free = vol["freeBytes"] as? UInt64 ?? 0
|
||||||
|
let used = vol["usedBytes"] as? UInt64 ?? 0
|
||||||
|
let pct = vol["usedPercent"] as? Double ?? 0
|
||||||
|
|
||||||
|
XCTAssertEqual(total, 512_000_000_000)
|
||||||
|
XCTAssertEqual(free, 204_800_000_000)
|
||||||
|
XCTAssertEqual(used, 307_200_000_000)
|
||||||
|
XCTAssertEqual(pct, 60.0, accuracy: 0.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLiveStorageProvider() throws {
|
||||||
|
let provider = MMStorageTelemetryProvider()
|
||||||
|
XCTAssertTrue(provider.isAvailable)
|
||||||
|
XCTAssertEqual(provider.domain, .storage)
|
||||||
|
|
||||||
|
let sample = try provider.sampleTelemetry()
|
||||||
|
let volumes = sample["volumes"] as? [[String: Any]]
|
||||||
|
XCTAssertNotNil(volumes)
|
||||||
|
XCTAssertGreaterThan(volumes?.count ?? 0, 0)
|
||||||
|
|
||||||
|
let firstVol = volumes?.first
|
||||||
|
XCTAssertNotNil(firstVol?["mountPoint"])
|
||||||
|
XCTAssertGreaterThan(firstVol?["totalBytes"] as? UInt64 ?? 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user