@@ -2365,6 +2365,144 @@ def set(_context, changes) end
23652365 described_class . register_transport ( schema )
23662366 end
23672367 end
2368+
2369+ describe 'finish method for class tag inheritance' , :agent_test do
2370+ let ( :definition ) do
2371+ {
2372+ name : 'tag_test' ,
2373+ desc : 'a test resource for tag inheritance' ,
2374+ attributes : {
2375+ name : {
2376+ type : 'String' ,
2377+ behaviour : :namevar ,
2378+ desc : 'the title'
2379+ } ,
2380+ ensure : {
2381+ type : 'Enum[present, absent]' ,
2382+ desc : 'the ensure value'
2383+ }
2384+ }
2385+ }
2386+ end
2387+ let ( :provider_class ) do
2388+ Class . new do
2389+ def get ( _context )
2390+ [ ]
2391+ end
2392+
2393+ def set ( _context , _changes ) ; end
2394+ end
2395+ end
2396+ let ( :type ) { Puppet ::Type . type ( :tag_test ) }
2397+ let ( :catalog ) { Puppet ::Resource ::Catalog . new }
2398+
2399+ before do
2400+ described_class . register_type ( definition )
2401+ stub_const ( 'Puppet::Provider::TagTest' , Module . new )
2402+ stub_const ( 'Puppet::Provider::TagTest::TagTest' , provider_class )
2403+ end
2404+
2405+ context 'when resource has pathbuilder with class names' do
2406+ let ( :instance ) { type . new ( name : 'test_resource' , ensure : 'present' ) }
2407+
2408+ before do
2409+ instance . catalog = catalog
2410+ allow ( instance ) . to receive ( :respond_to? ) . with ( :pathbuilder ) . and_return ( true )
2411+ allow ( instance ) . to receive ( :pathbuilder ) . and_return ( [ 'Stage[main]' , 'Test::MyClass' , 'Test::AnotherClass' , 'TagTest[test_resource]' ] )
2412+ end
2413+
2414+ it 'tags the resource with class names from pathbuilder' do
2415+ instance . finish
2416+ expect ( instance . tags . to_a ) . to include ( 'test::myclass' , 'test::anotherclass' , 'test' , 'anotherclass' , 'myclass' )
2417+ end
2418+
2419+ it 'does not tag resources that have brackets' do
2420+ instance . finish
2421+ expect ( instance . tags . to_a ) . not_to include ( 'stage[main]' )
2422+ expect ( instance . tags . to_a ) . not_to include ( 'tagtest[test_resource]' )
2423+ end
2424+ end
2425+
2426+ context 'when resource has pathbuilder with only resources (no classes)' do
2427+ let ( :instance ) { type . new ( name : 'test_resource2' , ensure : 'present' ) }
2428+
2429+ before do
2430+ instance . catalog = catalog
2431+ allow ( instance ) . to receive ( :respond_to? ) . with ( :pathbuilder ) . and_return ( true )
2432+ allow ( instance ) . to receive ( :pathbuilder ) . and_return ( [ 'Stage[main]' , 'TagTest[test_resource2]' ] )
2433+ end
2434+
2435+ it 'does not tag any classes' do
2436+ initial_tags = instance . tags . to_a
2437+ instance . finish
2438+ # Should only have the default tags, no class tags added
2439+ expect ( instance . tags . to_a - initial_tags ) . to be_empty
2440+ end
2441+ end
2442+
2443+ context 'when resource does not have pathbuilder' do
2444+ let ( :instance ) { type . new ( name : 'test_resource3' , ensure : 'present' ) }
2445+
2446+ before do
2447+ instance . catalog = catalog
2448+ allow ( instance ) . to receive ( :respond_to? ) . with ( :pathbuilder ) . and_return ( false )
2449+ end
2450+
2451+ it 'does not error' do
2452+ expect { instance . finish } . not_to raise_error
2453+ end
2454+ end
2455+
2456+ context 'when resource does not have a catalog' do
2457+ let ( :instance ) { type . new ( name : 'test_resource4' , ensure : 'present' ) }
2458+
2459+ before do
2460+ instance . catalog = nil
2461+ end
2462+
2463+ it 'returns early without processing' do
2464+ expect ( instance ) . not_to receive ( :pathbuilder )
2465+ instance . finish
2466+ end
2467+ end
2468+
2469+ context 'when pathbuilder returns mixed case class names' do
2470+ let ( :instance ) { type . new ( name : 'test_resource5' , ensure : 'present' ) }
2471+
2472+ before do
2473+ instance . catalog = catalog
2474+ allow ( instance ) . to receive ( :respond_to? ) . with ( :pathbuilder ) . and_return ( true )
2475+ allow ( instance ) . to receive ( :pathbuilder ) . and_return ( [ 'MyModule::MyClass' , 'AnotherModule' ] )
2476+ end
2477+
2478+ it 'normalizes class names to lowercase when tagging' do
2479+ instance . finish
2480+ # Puppet's tag() method automatically lowercases
2481+ expect ( instance . tags . to_a ) . to include ( 'mymodule::myclass' , 'anothermodule' , 'mymodule' , 'myclass' )
2482+ end
2483+ end
2484+
2485+ context 'when pathbuilder returns nested classes' do
2486+ let ( :instance ) { type . new ( name : 'test_resource6' , ensure : 'present' ) }
2487+
2488+ before do
2489+ instance . catalog = catalog
2490+ allow ( instance ) . to receive ( :respond_to? ) . with ( :pathbuilder ) . and_return ( true )
2491+ allow ( instance ) . to receive ( :pathbuilder ) . and_return ( [
2492+ 'Stage[main]' ,
2493+ 'Profiles::Base' ,
2494+ 'Profiles::Web' ,
2495+ 'Profiles::Web::Apache' ,
2496+ 'TagTest[test_resource6]'
2497+ ] )
2498+ end
2499+
2500+ it 'tags all classes in the containment hierarchy' do
2501+ instance . finish
2502+ expect ( instance . tags . to_a ) . to include ( 'profiles::base' , 'profiles::web' , 'profiles::web::apache' , 'profiles' , 'web' , 'base' , 'apache' )
2503+ end
2504+ end
2505+ end
23682506end
23692507
23702508# rubocop:enable Lint/ConstantDefinitionInBlock
0 commit comments