Skip to content

Commit

Permalink
Extended SystemHotSwapper to allow swapping one system (implementing …
Browse files Browse the repository at this point in the history
…several interfaces) with more than one replacement systems.
  • Loading branch information
gcotelli committed Nov 1, 2019
1 parent 4df264e commit 896cea6
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 40 deletions.
32 changes: 32 additions & 0 deletions source/Kepler-System-Tests/FixedCustomerManagementSystem.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"
I'm a system implementation failing when trying to add a customer. Used for testing purposes.
"
Class {
#name : #FixedCustomerManagementSystem,
#superclass : #SubsystemImplementation,
#category : #'Kepler-System-Tests'
}

{ #category : #API }
FixedCustomerManagementSystem >> addCustomer: aCustomer [

SystemCommandExecutionError signal: 'Cannot add customer'
]

{ #category : #installing }
FixedCustomerManagementSystem >> dependencies [

^ #()
]

{ #category : #installing }
FixedCustomerManagementSystem >> implementedInterfaces [

^ #(#CustomerManagementSystem)
]

{ #category : #installing }
FixedCustomerManagementSystem >> name [

^ 'CMS'
]
138 changes: 114 additions & 24 deletions source/Kepler-System-Tests/SystemHotSwapperTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -4,73 +4,163 @@ SystemHotSwapper test case
Class {
#name : #SystemHotSwapperTest,
#superclass : #TestCase,
#instVars : [
'composite'
],
#category : #'Kepler-System-Tests'
}

{ #category : #tests }
SystemHotSwapperTest >> testCantSwapWhenTheInterfaceIsNotImplemented [
{ #category : #private }
SystemHotSwapperTest >> assert: aSubsystem implements: anInterfaceKey [

| composite cms newCMS |
self assert: ( self is: anInterfaceKey implementedBy: aSubsystem )
]

cms := SampleCustomerSystem new.
{ #category : #private }
SystemHotSwapperTest >> deny: aSubsystem implements: anInterfaceKey [

self deny: ( self is: anInterfaceKey implementedBy: aSubsystem )
]

{ #category : #private }
SystemHotSwapperTest >> is: anInterfaceKey implementedBy: aSubsystem [

^ aSubsystem implements: ( composite interfaceAt: anInterfaceKey )
]

{ #category : #running }
SystemHotSwapperTest >> setUp [

super setUp.
composite := CompositeSystem new
register: cms;
yourself.
composite startUp.
]

newCMS := FixedCustomerSystem new.
{ #category : #running }
SystemHotSwapperTest >> tearDown [

composite shutDown.
super tearDown
]

{ #category : #tests }
SystemHotSwapperTest >> testCantSwapWhenTheInterfaceIsNotImplemented [

composite
register: SampleCustomerSystem new;
startUp.

self
should: [ (SystemHotSwapper swapSystemImplementing: #CustomerManagementSystem with: newCMS) applyTo: composite ]
should: [ SystemHotSwapper swapSystemImplementing: #CustomerManagementSystem with: FixedCustomerSystem new ]
raise: SystemControlError
withMessageText: 'CMS is not implementing Customer Management'
]

{ #category : #tests }
SystemHotSwapperTest >> testSwapping [

| composite cms newCMS |
| cms newCMS |

cms := SampleCustomerSystem new.
composite := CompositeSystem new
composite
register: cms;
yourself.
composite startUp.
startUp.

cms addCustomer: 'John'.

newCMS := FixedCustomerSystem new.

self deny: cms = newCMS.

self
assert: composite >> #CustomerQueryingSystem equals: cms;
assert: (composite >> #CustomerQueryingSystem) customers size equals: 1.
assert: ( composite >> #CustomerQueryingSystem ) customers size equals: 1.

(SystemHotSwapper swapSystemImplementing: #CustomerQueryingSystem with: newCMS) applyTo: composite.
( SystemHotSwapper swapSystemImplementing: #CustomerQueryingSystem with: newCMS )
applyTo: composite.

self
assert: composite >> #CustomerQueryingSystem equals: newCMS;
assert: (composite >> #CustomerQueryingSystem) customers size equals: 2
assert: ( composite >> #CustomerQueryingSystem ) customers size equals: 2
]

{ #category : #tests }
SystemHotSwapperTest >> testSwappingFailedWhenReplacementsAreMissingSomeInterfaces [

| cms pms swapper |

cms := SampleCustomerSystem new.
pms := SampleProjectSystem new.
composite
register: cms;
register: pms;
startUp.

self
assert: composite >> #CustomerManagementSystem equals: cms;
assert: pms >> #CustomerQueryingSystem equals: cms.

swapper := SystemHotSwapper
swapSystemImplementing: #CustomerManagementSystem
with: FixedCustomerManagementSystem new.

self
should: [ swapper applyTo: composite ]
raise: SystemControlError
withMessageText: 'System implementing "Customer Querying" not found.'
]

{ #category : #tests }
SystemHotSwapperTest >> testSwappingOneImplementationWithTwoOthers [

"This test checks that a system implementing more than one interface can be replaced
by two or more systems implementing the required interfaces"

| cms managementSystem queryingSystem |

cms := SampleCustomerSystem new.
composite
register: cms;
startUp.

self
assert: cms implements: #CustomerQueryingSystem;
assert: cms implements: #CustomerManagementSystem.

managementSystem := FixedCustomerManagementSystem new.
self
assert: managementSystem implements: #CustomerManagementSystem;
deny: managementSystem implements: #CustomerQueryingSystem.

queryingSystem := FixedCustomerSystem new.
self
assert: queryingSystem implements: #CustomerQueryingSystem;
deny: queryingSystem implements: #CustomerManagementSystem.

self
assert: composite >> #CustomerQueryingSystem equals: cms;
assert: composite >> #CustomerManagementSystem equals: cms.

( SystemHotSwapper
swapSystemImplementingAll: #(#CustomerQueryingSystem #CustomerManagementSystem)
with: ( Array with: queryingSystem with: managementSystem ) ) applyTo: composite.

self
assert: composite >> #CustomerQueryingSystem equals: queryingSystem;
assert: composite >> #CustomerManagementSystem equals: managementSystem
]

{ #category : #tests }
SystemHotSwapperTest >> testSwappingSystemWithDependents [

| composite cms newCMS pms |
| cms newCMS pms |

cms := SampleCustomerSystem new.
pms := SampleProjectSystem new.
composite := CompositeSystem new
composite
register: cms;
register: pms;
yourself.
composite startUp.
startUp.

newCMS := FixedCustomerSystem new.

self deny: cms = newCMS.

self
assert: composite >> #CustomerQueryingSystem equals: cms;
assert: pms >> #CustomerQueryingSystem equals: cms.
Expand Down
21 changes: 15 additions & 6 deletions source/Kepler-System/SystemHotInstaller.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,36 @@ Class {
#name : #SystemHotInstaller,
#superclass : #Object,
#instVars : [
'subsystem'
'subsystems'
],
#category : #'Kepler-System'
}

{ #category : #'instance creation' }
SystemHotInstaller class >> installing: aSubsystem [

^self new initializeInstalling: aSubsystem
^ self installingAll: {aSubsystem}
]

{ #category : #'instance creation' }
SystemHotInstaller class >> installingAll: aSubsystemCollection [

^self new initializeInstallingAll: aSubsystemCollection
]

{ #category : #applying }
SystemHotInstaller >> applyTo: aCompositeSystem [

aCompositeSystem register: subsystem.
subsystem startUp.
subsystems
do: [ :subsystem |
aCompositeSystem register: subsystem.
subsystem startUp
].
aCompositeSystem resolveSubsystemDependencies
]

{ #category : #initialization }
SystemHotInstaller >> initializeInstalling: aSubsystem [
SystemHotInstaller >> initializeInstallingAll: aSubsystemCollection [

subsystem := aSubsystem
subsystems := aSubsystemCollection
]
40 changes: 30 additions & 10 deletions source/Kepler-System/SystemHotSwapper.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Class {
#name : #SystemHotSwapper,
#superclass : #Object,
#instVars : [
'subsystem',
'interfaceKey'
'interfaceKey',
'subsystems'
],
#pools : [
'Kepler'
Expand All @@ -15,17 +15,37 @@ Class {
}

{ #category : #'private - preconditions' }
SystemHotSwapper class >> assert: aSubsystem implements: anInterfaceKey [
SystemHotSwapper class >> assert: aSubsystem implementsAnyIn: anInterfaceKeyCollection [

(SystemInterfaces >> anInterfaceKey isImplementedBy: aSubsystem)
ifFalse: [ SystemControlError signal: ('<1p> is not implementing <2p>' expandMacrosWith: aSubsystem with: SystemInterfaces >> anInterfaceKey) ]
anInterfaceKeyCollection
detect: [ :anInterfaceKey | SystemInterfaces >> anInterfaceKey isImplementedBy: aSubsystem ]
ifNone: [ SystemControlError
signal:
( '<1p> is not implementing <2s>'
expandMacrosWith: aSubsystem
with:
( ( CollectionFormatter
separatingWith: $,
applyingToEach: [ :anInterfaceKey | ( SystemInterfaces >> anInterfaceKey ) printString ] )
format: anInterfaceKeyCollection ) )
]
]

{ #category : #'instance creation' }
SystemHotSwapper class >> swapSystemImplementing: anInterfaceKey with: aSubsystem [

self assert: aSubsystem implements: anInterfaceKey.
^self new initializeSwapSystemImplementing: anInterfaceKey with: aSubsystem
^ self swapSystemImplementingAll: {anInterfaceKey} with: {aSubsystem}
]

{ #category : #'instance creation' }
SystemHotSwapper class >> swapSystemImplementingAll: anInterfaceKeyCollection with: aSubsystemCollection [

aSubsystemCollection
do: [ :aSubsystem | self assert: aSubsystem implementsAnyIn: anInterfaceKeyCollection ].

^ self new
initializeSwapSystemImplementing: anInterfaceKeyCollection anyOne
withAll: aSubsystemCollection
]

{ #category : #applying }
Expand All @@ -36,12 +56,12 @@ SystemHotSwapper >> applyTo: aCompositeSystem [
subsystemToSwap := aCompositeSystem >> interfaceKey.
subsystemToSwap shutDown.
aCompositeSystem unregister: subsystemToSwap.
(SystemHotInstaller installing: subsystem) applyTo: aCompositeSystem
( SystemHotInstaller installingAll: subsystems ) applyTo: aCompositeSystem
]

{ #category : #initialization }
SystemHotSwapper >> initializeSwapSystemImplementing: anInterfaceKey with: aSubsystem [
SystemHotSwapper >> initializeSwapSystemImplementing: anInterfaceKey withAll: aSubsystemCollection [

interfaceKey := anInterfaceKey.
subsystem := aSubsystem
subsystems := aSubsystemCollection
]

0 comments on commit 896cea6

Please sign in to comment.