55
66use std:: sync:: { Arc , Mutex } ;
77
8- use crate :: presentation:: commands:: constants:: DEFAULT_VERBOSITY ;
9- use crate :: presentation:: user_output:: UserOutput ;
8+ use crate :: infrastructure:: persistence:: repository_factory:: RepositoryFactory ;
9+ use crate :: presentation:: commands:: constants:: DEFAULT_LOCK_TIMEOUT ;
10+ use crate :: presentation:: user_output:: { UserOutput , VerbosityLevel } ;
11+ use crate :: shared:: clock:: Clock ;
12+ use crate :: shared:: SystemClock ;
1013
1114/// Application service container
1215///
1316/// Holds shared services initialized during application bootstrap.
14- /// Services are wrapped in `Arc<Mutex<T> >` for thread-safe shared ownership
15- /// with interior mutability across the application.
17+ /// Services are wrapped in `Arc<T >` for thread-safe shared ownership
18+ /// across the application.
1619///
1720/// # Example
1821///
1922/// ```rust
2023/// use torrust_tracker_deployer_lib::bootstrap::container::Container;
24+ /// use torrust_tracker_deployer_lib::presentation::user_output::VerbosityLevel;
2125///
22- /// let container = Container::new();
26+ /// let container = Container::new(VerbosityLevel::Normal );
2327/// let user_output = container.user_output();
2428/// user_output.lock().unwrap().success("Operation completed");
2529/// ```
2630#[ derive( Clone ) ]
2731pub struct Container {
2832 user_output : Arc < Mutex < UserOutput > > ,
33+ repository_factory : Arc < RepositoryFactory > ,
34+ clock : Arc < dyn Clock > ,
2935}
3036
3137impl Container {
3238 /// Create a new container with initialized services
3339 ///
34- /// Uses `DEFAULT_VERBOSITY` for user output. In the future, this may
35- /// accept a verbosity parameter from CLI flags.
40+ /// Initializes all services with specified verbosity level:
41+ /// - `UserOutput` with provided `verbosity_level`
42+ /// - `RepositoryFactory` with `DEFAULT_LOCK_TIMEOUT`
43+ /// - `SystemClock` for time operations
44+ ///
45+ /// # Arguments
46+ ///
47+ /// * `verbosity_level` - Controls how verbose the user output will be
48+ ///
49+ /// # Examples
50+ ///
51+ /// ```rust
52+ /// use torrust_tracker_deployer_lib::bootstrap::container::Container;
53+ /// use torrust_tracker_deployer_lib::presentation::user_output::VerbosityLevel;
54+ ///
55+ /// // For normal application use
56+ /// let container = Container::new(VerbosityLevel::Normal);
57+ ///
58+ /// // For completely silent testing
59+ /// let container = Container::new(VerbosityLevel::Silent);
60+ /// ```
3661 #[ must_use]
37- pub fn new ( ) -> Self {
38- let user_output = Arc :: new ( Mutex :: new ( UserOutput :: new ( DEFAULT_VERBOSITY ) ) ) ;
62+ pub fn new ( verbosity_level : VerbosityLevel ) -> Self {
63+ let user_output = Arc :: new ( Mutex :: new ( UserOutput :: new ( verbosity_level) ) ) ;
64+ let repository_factory = Arc :: new ( RepositoryFactory :: new ( DEFAULT_LOCK_TIMEOUT ) ) ;
65+ let clock: Arc < dyn Clock > = Arc :: new ( SystemClock ) ;
3966
40- Self { user_output }
67+ Self {
68+ user_output,
69+ repository_factory,
70+ clock,
71+ }
4172 }
4273
4374 /// Get shared reference to user output service
@@ -49,20 +80,61 @@ impl Container {
4980 ///
5081 /// ```rust
5182 /// use torrust_tracker_deployer_lib::bootstrap::container::Container;
83+ /// use torrust_tracker_deployer_lib::presentation::user_output::VerbosityLevel;
5284 ///
53- /// let container = Container::new();
85+ /// let container = Container::new(VerbosityLevel::Normal );
5486 /// let user_output = container.user_output();
5587 /// user_output.lock().unwrap().success("Operation completed");
5688 /// ```
5789 #[ must_use]
5890 pub fn user_output ( & self ) -> Arc < Mutex < UserOutput > > {
5991 Arc :: clone ( & self . user_output )
6092 }
93+
94+ /// Get shared reference to repository factory service
95+ ///
96+ /// Returns an `Arc<RepositoryFactory>` that can be cheaply cloned and shared
97+ /// across threads and function calls.
98+ ///
99+ /// # Example
100+ ///
101+ /// ```rust
102+ /// use torrust_tracker_deployer_lib::bootstrap::container::Container;
103+ /// use torrust_tracker_deployer_lib::presentation::user_output::VerbosityLevel;
104+ ///
105+ /// let container = Container::new(VerbosityLevel::Normal);
106+ /// let repository_factory = container.repository_factory();
107+ /// // Use repository_factory to create repositories
108+ /// ```
109+ #[ must_use]
110+ pub fn repository_factory ( & self ) -> Arc < RepositoryFactory > {
111+ Arc :: clone ( & self . repository_factory )
112+ }
113+
114+ /// Get shared reference to clock service
115+ ///
116+ /// Returns an `Arc<dyn Clock>` that can be cheaply cloned and shared
117+ /// across threads and function calls.
118+ ///
119+ /// # Example
120+ ///
121+ /// ```rust
122+ /// use torrust_tracker_deployer_lib::bootstrap::container::Container;
123+ /// use torrust_tracker_deployer_lib::presentation::user_output::VerbosityLevel;
124+ ///
125+ /// let container = Container::new(VerbosityLevel::Normal);
126+ /// let clock = container.clock();
127+ /// // Use clock for time operations
128+ /// ```
129+ #[ must_use]
130+ pub fn clock ( & self ) -> Arc < dyn Clock > {
131+ Arc :: clone ( & self . clock )
132+ }
61133}
62134
63135impl Default for Container {
64136 fn default ( ) -> Self {
65- Self :: new ( )
137+ Self :: new ( VerbosityLevel :: Normal )
66138 }
67139}
68140
@@ -71,17 +143,42 @@ mod tests {
71143 use super :: * ;
72144
73145 #[ test]
74- fn it_should_create_container_with_user_output ( ) {
75- let container = Container :: new ( ) ;
146+ fn it_should_create_container_with_all_services ( ) {
147+ let container = Container :: new ( VerbosityLevel :: Normal ) ;
148+
149+ // Verify we can get all services
76150 let user_output = container. user_output ( ) ;
151+ let repository_factory = container. repository_factory ( ) ;
152+ let clock = container. clock ( ) ;
77153
78- // Verify we can get the user_output service
79154 assert ! ( Arc :: strong_count( & user_output) >= 1 ) ;
155+ assert ! ( Arc :: strong_count( & repository_factory) >= 1 ) ;
156+ assert ! ( Arc :: strong_count( & clock) >= 1 ) ;
157+ }
158+
159+ #[ test]
160+ fn it_should_return_cloned_arc_on_repository_factory_access ( ) {
161+ let container = Container :: new ( VerbosityLevel :: Normal ) ;
162+ let factory1 = container. repository_factory ( ) ;
163+ let factory2 = container. repository_factory ( ) ;
164+
165+ // Both should point to the same RepositoryFactory instance
166+ assert ! ( Arc :: ptr_eq( & factory1, & factory2) ) ;
167+ }
168+
169+ #[ test]
170+ fn it_should_return_cloned_arc_on_clock_access ( ) {
171+ let container = Container :: new ( VerbosityLevel :: Normal ) ;
172+ let clock1 = container. clock ( ) ;
173+ let clock2 = container. clock ( ) ;
174+
175+ // Both should point to the same Clock instance
176+ assert ! ( Arc :: ptr_eq( & clock1, & clock2) ) ;
80177 }
81178
82179 #[ test]
83180 fn it_should_return_cloned_arc_on_user_output_access ( ) {
84- let container = Container :: new ( ) ;
181+ let container = Container :: new ( VerbosityLevel :: Normal ) ;
85182 let user_output1 = container. user_output ( ) ;
86183 let user_output2 = container. user_output ( ) ;
87184
@@ -91,13 +188,63 @@ mod tests {
91188
92189 #[ test]
93190 fn it_should_be_clonable ( ) {
94- let container1 = Container :: new ( ) ;
191+ let container1 = Container :: new ( VerbosityLevel :: Normal ) ;
95192 let container2 = container1. clone ( ) ;
96193
194+ // Cloned containers should share all services
97195 let user_output1 = container1. user_output ( ) ;
98196 let user_output2 = container2. user_output ( ) ;
99-
100- // Cloned containers should share the same UserOutput
101197 assert ! ( Arc :: ptr_eq( & user_output1, & user_output2) ) ;
198+
199+ let factory1 = container1. repository_factory ( ) ;
200+ let factory2 = container2. repository_factory ( ) ;
201+ assert ! ( Arc :: ptr_eq( & factory1, & factory2) ) ;
202+
203+ let clock1 = container1. clock ( ) ;
204+ let clock2 = container2. clock ( ) ;
205+ assert ! ( Arc :: ptr_eq( & clock1, & clock2) ) ;
206+ }
207+
208+ #[ test]
209+ fn it_should_create_container_with_silent_verbosity_for_tests ( ) {
210+ let container = Container :: new ( VerbosityLevel :: Silent ) ;
211+
212+ // All services should be available
213+ let user_output = container. user_output ( ) ;
214+ let repository_factory = container. repository_factory ( ) ;
215+ let clock = container. clock ( ) ;
216+
217+ assert ! ( Arc :: strong_count( & user_output) >= 1 ) ;
218+ assert ! ( Arc :: strong_count( & repository_factory) >= 1 ) ;
219+ assert ! ( Arc :: strong_count( & clock) >= 1 ) ;
220+
221+ // The container should work with any verbosity level, including Silent for tests
222+ // Silent mode will suppress all output, making tests clean
223+ }
224+
225+ #[ test]
226+ fn it_should_create_container_with_different_verbosity_levels ( ) {
227+ // Test all available verbosity levels
228+ let levels = [
229+ VerbosityLevel :: Silent ,
230+ VerbosityLevel :: Quiet ,
231+ VerbosityLevel :: Normal ,
232+ VerbosityLevel :: Verbose ,
233+ VerbosityLevel :: VeryVerbose ,
234+ VerbosityLevel :: Debug ,
235+ ] ;
236+
237+ for level in & levels {
238+ let container = Container :: new ( * level) ;
239+
240+ // All services should be available regardless of verbosity level
241+ let user_output = container. user_output ( ) ;
242+ let repository_factory = container. repository_factory ( ) ;
243+ let clock = container. clock ( ) ;
244+
245+ assert ! ( Arc :: strong_count( & user_output) >= 1 ) ;
246+ assert ! ( Arc :: strong_count( & repository_factory) >= 1 ) ;
247+ assert ! ( Arc :: strong_count( & clock) >= 1 ) ;
248+ }
102249 }
103250}
0 commit comments