Skip to content

Commit

Permalink
prepare 8.3.1 release (#318)
Browse files Browse the repository at this point in the history
## [8.3.1] - 2023-10-31
### Changed:
- Calling `identify()` with the current context is now more efficient
and no longer results in re-establishing a connection.

### Fixed:
- Fixed issue where flag change listeners were not being triggered when
`identify()` was called.

---------

Co-authored-by: Ben Woskow <[email protected]>
Co-authored-by: torchhound <[email protected]>
Co-authored-by: Gavin Whelan <[email protected]>
Co-authored-by: Louis Chan <[email protected]>
Co-authored-by: Matthew Keeler <[email protected]>
Co-authored-by: Louis Chan <[email protected]>
Co-authored-by: Ember Stevens <[email protected]>
Co-authored-by: Ember Stevens <[email protected]>
Co-authored-by: Ryan Lamb <[email protected]>
Co-authored-by: ld-repository-standards[bot] <113625520+ld-repository-standards[bot]@users.noreply.github.com>
Co-authored-by: Kane Parkinson <[email protected]>
  • Loading branch information
12 people authored Oct 31, 2023
1 parent 89f5d3e commit 89d87b2
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 18 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to the LaunchDarkly iOS SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).

## [8.3.1] - 2023-10-31
### Changed:
- Calling `identify()` with the current context is now more efficient and no longer results in re-establishing a connection.

### Fixed:
- Fixed issue where flag change listeners were not being triggered when `identify()` was called.

## [8.3.0] - 2023-09-08
### Changed:
- Deprecated `LDValue.init(integerLiteral: Double)` as this method signature is misleading. A new `LDValue.init(integerLiteral: Int)` signature has been added for clarity.
Expand Down
2 changes: 1 addition & 1 deletion LaunchDarkly.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Pod::Spec.new do |ld|

ld.name = "LaunchDarkly"
ld.version = "8.3.0"
ld.version = "8.3.1"
ld.summary = "iOS SDK for LaunchDarkly"

ld.description = <<-DESC
Expand Down
20 changes: 10 additions & 10 deletions LaunchDarkly.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1503,7 +1503,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 8.3.0;
MARKETING_VERSION = 8.3.1;
MODULEMAP_FILE = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-tvOS";
PRODUCT_NAME = LaunchDarkly_tvOS;
Expand All @@ -1526,7 +1526,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 8.3.0;
MARKETING_VERSION = 8.3.1;
MODULEMAP_FILE = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-tvOS";
PRODUCT_NAME = LaunchDarkly_tvOS;
Expand All @@ -1549,7 +1549,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 8.3.0;
MARKETING_VERSION = 8.3.1;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-macOS";
PRODUCT_NAME = LaunchDarkly_macOS;
SDKROOT = macosx;
Expand All @@ -1570,7 +1570,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 8.3.0;
MARKETING_VERSION = 8.3.1;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-macOS";
PRODUCT_NAME = LaunchDarkly_macOS;
SDKROOT = macosx;
Expand Down Expand Up @@ -1614,7 +1614,7 @@
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 8.0.0;
DYLIB_CURRENT_VERSION = 8.3.0;
DYLIB_CURRENT_VERSION = 8.3.1;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_VERSION = E;
Expand Down Expand Up @@ -1685,7 +1685,7 @@
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 8.0.0;
DYLIB_CURRENT_VERSION = 8.3.0;
DYLIB_CURRENT_VERSION = 8.3.1;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_VERSION = E;
Expand Down Expand Up @@ -1724,7 +1724,7 @@
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
MARKETING_VERSION = 8.3.0;
MARKETING_VERSION = 8.3.1;
MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.Darkly;
PRODUCT_NAME = LaunchDarkly;
Expand All @@ -1744,7 +1744,7 @@
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
MARKETING_VERSION = 8.3.0;
MARKETING_VERSION = 8.3.1;
MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.Darkly;
PRODUCT_NAME = LaunchDarkly;
Expand Down Expand Up @@ -1786,7 +1786,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 8.3.0;
MARKETING_VERSION = 8.3.1;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-watchOS";
PRODUCT_NAME = LaunchDarkly_watchOS;
SDKROOT = watchos;
Expand All @@ -1808,7 +1808,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "$(PROJECT_DIR)/LaunchDarkly/LaunchDarkly/Support/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
MARKETING_VERSION = 8.3.0;
MARKETING_VERSION = 8.3.1;
PRODUCT_BUNDLE_IDENTIFIER = "com.launchdarkly.Darkly-watchOS";
PRODUCT_NAME = LaunchDarkly_watchOS;
SDKROOT = watchos;
Expand Down
8 changes: 8 additions & 0 deletions LaunchDarkly/LaunchDarkly/LDClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -303,13 +303,21 @@ public class LDClient {

func internalIdentify(newContext: LDContext, completion: (() -> Void)? = nil) {
internalIdentifyQueue.sync {
if self.context == newContext {
self.eventReporter.record(IdentifyEvent(context: self.context))
completion?()
return
}

self.context = newContext
Log.debug(self.typeName(and: #function) + "new context set with key: " + self.context.fullyQualifiedKey() )
let wasOnline = self.isOnline
self.internalSetOnline(false)

let cachedContextFlags = self.flagCache.retrieveFeatureFlags(contextKey: self.context.fullyQualifiedHashedKey()) ?? [:]
let oldItems = flagStore.storedItems.featureFlags
flagStore.replaceStore(newStoredItems: cachedContextFlags)
flagChangeNotifier.notifyObservers(oldFlags: oldItems, newFlags: flagStore.storedItems.featureFlags)
self.service.context = self.context
self.service.clearFlagResponseCache()
flagSynchronizer = serviceFactory.makeFlagSynchronizer(streamingMode: ConnectionInformation.effectiveStreamingMode(config: config, ldClient: self),
Expand Down
8 changes: 7 additions & 1 deletion LaunchDarkly/LaunchDarkly/Models/Context/Reference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ extension ReferenceError: CustomStringConvertible {
/// - Reference("name") or Reference("/name") would refer to the value "xyz"
/// - Reference("/address/street") would refer to the value "99 Main St."
/// - Reference("a/b") or Reference("/a~1b") would refer to the value "ok"
public struct Reference: Codable, Equatable, Hashable {
public struct Reference: Codable, Hashable {
private var error: ReferenceError?
private var rawPath: String
private var components: [String] = []
Expand Down Expand Up @@ -230,3 +230,9 @@ public struct Reference: Codable, Equatable, Hashable {
return self.components[index]
}
}

extension Reference: Equatable {
public static func == (lhs: Reference, rhs: Reference) -> Bool {
return lhs.error == rhs.error && lhs.components == rhs.components
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ struct EnvironmentReporter: EnvironmentReporting {
#endif

var shouldThrottleOnlineCalls: Bool { !isDebugBuild }
let sdkVersion = "8.3.0"
let sdkVersion = "8.3.1"
// Unfortunately, the following does not function in certain configurations, such as when included through SPM
// var sdkVersion: String {
// Bundle(for: LDClient.self).infoDictionary?["CFBundleShortVersionString"] as? String ?? "5.x"
Expand Down
18 changes: 18 additions & 0 deletions LaunchDarkly/LaunchDarklyTests/LDClientSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,24 @@ final class LDClientSpec: QuickSpec {
expect(testContext.flagStoreMock.replaceStoreCallCount) == 1
expect(testContext.flagStoreMock.replaceStoreReceivedNewFlags) == stubFlags
}
it("only triggered if context is different") {
let testContext = TestContext(startOnline: true)
testContext.start()
testContext.featureFlagCachingMock.reset()

testContext.subject.internalIdentify(newContext: testContext.context)
testContext.subject.internalIdentify(newContext: testContext.context)
testContext.subject.internalIdentify(newContext: testContext.context)
testContext.subject.internalIdentify(newContext: testContext.context)

expect(testContext.flagStoreMock.replaceStoreCallCount) == 0
expect(testContext.makeFlagSynchronizerService?.context) == testContext.context

expect(testContext.subject.isOnline) == true
expect(testContext.subject.eventReporter.isOnline) == true
expect(testContext.subject.flagSynchronizer.isOnline) == true
expect(testContext.eventReporterMock.recordReceivedEvent?.kind == .identify).to(beTrue())
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,17 @@ final class LDContextCodableSpec: XCTestCase {

func testSingleContextKindsAreDecodedAndEncodedWithoutLossOfInformation() throws {
let testCases = [
"{\"kind\":\"org\",\"key\":\"foo\"}",
"{\"kind\":\"user\",\"key\":\"foo\"}",
"{\"kind\":\"foo\",\"key\":\"bar\",\"anonymous\":true}",
"{\"kind\":\"foo\",\"key\":\"bar\",\"name\":\"Foo\",\"_meta\":{\"privateAttributes\":[\"a\"]}}",
"{\"kind\":\"foo\",\"key\":\"bar\",\"object\":{\"a\":\"b\"}}"
"{\"key\":\"foo\",\"kind\":\"org\"}",
"{\"key\":\"foo\",\"kind\":\"user\"}",
"{\"anonymous\":true,\"key\":\"bar\",\"kind\":\"foo\"}",
"{\"_meta\":{\"privateAttributes\":[\"a\"]},\"key\":\"bar\",\"kind\":\"foo\",\"name\":\"Foo\"}",
"{\"key\":\"bar\",\"kind\":\"foo\",\"object\":{\"a\":\"b\"}}"
]

for json in testCases {
let context = try JSONDecoder().decode(LDContext.self, from: Data(json.utf8))
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = [.sortedKeys]
jsonEncoder.userInfo = [LDContext.UserInfoKeys.includePrivateAttributes:true]
let output = try jsonEncoder.encode(context)
let outputJson = String(data: output, encoding: .utf8)
Expand Down
41 changes: 41 additions & 0 deletions LaunchDarkly/LaunchDarklyTests/Models/Context/LDContextSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,47 @@ import XCTest
@testable import LaunchDarkly

final class LDContextSpec: XCTestCase {
func testContextsAreEquatable() throws {
var originalBuilder = LDContextBuilder(key: "context-key")
originalBuilder.kind("user")
originalBuilder.name("Example name")
originalBuilder.trySetValue("groups", LDValue.array(["test", "it", "here"]))
originalBuilder.trySetValue("address", LDValue.object(["address": "123 Easy St", "city": "Every Town"]))
originalBuilder.addPrivateAttribute(Reference(literal: "name"))

var duplicateBuilder = LDContextBuilder(key: "context-key")
duplicateBuilder.kind("user")
duplicateBuilder.name("Example name")
duplicateBuilder.trySetValue("groups", LDValue.array(["test", "it", "here"]))
duplicateBuilder.trySetValue("address", LDValue.object(["address": "123 Easy St", "city": "Every Town"]))
duplicateBuilder.addPrivateAttribute(Reference("/name"))

let original = try originalBuilder.build().get()
let duplicate = try duplicateBuilder.build().get()

XCTAssertEqual(original, duplicate)
}

func testContextsAreNotTheSame() throws {
let values: [String: LDValue] = [
"kind": "org",
"name": "Example name",
"groups": "This is a string",
"address": LDValue.array(["wrong type again"])
]

for (name, value) in values {
var originalBuilder = LDContextBuilder(key: "context-key")
var slightlyDifferent = LDContextBuilder(key: "context-key")
slightlyDifferent.trySetValue(name, value)

let original = try originalBuilder.build().get()
let duplicate = try slightlyDifferent.build().get()

XCTAssertNotEqual(original, duplicate)
}
}

func testBuildCanCreateSimpleContext() throws {
var builder = LDContextBuilder(key: "context-key")
builder.name("Name")
Expand Down
18 changes: 18 additions & 0 deletions LaunchDarkly/LaunchDarklyTests/Models/Context/ReferenceSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ import XCTest
@testable import LaunchDarkly

final class ReferenceSpec: XCTestCase {
func testVerifyEquality() {
let tests: [(Reference, Reference, Bool)] = [
(Reference("name"), Reference("name"), true),
(Reference("name"), Reference("/name"), true),
(Reference("/first/name"), Reference("/first/name"), true),
(Reference(literal: "/name"), Reference(literal: "/name"), true),
(Reference(literal: "/name"), Reference("/~1name"), true),
(Reference(literal: "~name"), Reference("/~0name"), true),

(Reference("different"), Reference("values"), false),
(Reference("name/"), Reference("/name"), false),
(Reference("/first/name"), Reference("/first//name"), false)
]

for (lhs, rhs, expected) in tests {
XCTAssertEqual(lhs == rhs, expected)
}
}
func testFailsWithCorrectError() {
let tests: [(String, ReferenceError)] = [
("", .empty),
Expand Down

0 comments on commit 89d87b2

Please sign in to comment.