commit 0412ca1fee585a739a736b36c32eb7db112a7ed3
Author: Greg Sutcliffe <gsutclif@redhat.com>
Date:   Wed Apr 30 12:59:07 2014 +0100

    Fixes #4287 - Join directly to template_combinations when resolving templates
    
    (cherry picked from commit 1443ec139bdb0a31faeef80f6c177d4f30fa4bdb)

diff --git a/app/models/config_template.rb b/app/models/config_template.rb
index ce448ddee..c6703eaa5 100644
--- a/app/models/config_template.rb
+++ b/app/models/config_template.rb
@@ -55,22 +55,27 @@ class ConfigTemplate < ActiveRecord::Base
     # first filter valid templates to our OS and requested template kind.
     templates = ConfigTemplate.joins(:operatingsystems, :template_kind).where('operatingsystems.id' => opts[:operatingsystem_id], 'template_kinds.name' => opts[:kind])
 
-
     # once a template has been matched, we no longer look for others.
 
     if opts[:hostgroup_id] and opts[:environment_id]
       # try to find a full match to our host group and environment
-      template = templates.joins(:hostgroups, :environments).where("hostgroups.id" => opts[:hostgroup_id], "environments.id" => opts[:environment_id]).first
+      template ||= templates.joins(:template_combinations).where(
+        "template_combinations.hostgroup_id" => opts[:hostgroup_id],
+        "template_combinations.environment_id" => opts[:environment_id]).first
     end
 
     if opts[:hostgroup_id]
       # try to find a match with our hostgroup only
-      template ||= templates.joins(:hostgroups).where("hostgroups.id" => opts[:hostgroup_id]).first
+      template ||= templates.joins(:template_combinations).where(
+        "template_combinations.hostgroup_id" => opts[:hostgroup_id],
+        "template_combinations.environment_id" => nil).first
     end
 
     if opts[:environment_id]
       # search for a template based only on our environment
-      template ||= templates.joins(:environments).where("environments.id" => opts[:environment_id]).first
+      template ||= templates.joins(:template_combinations).where(
+        "template_combinations.hostgroup_id" => nil,
+        "template_combinations.environment_id" => opts[:environment_id]).first
     end
 
     # fall back to the os default template
diff --git a/test/factories/config_template.rb b/test/factories/config_template.rb
new file mode 100644
index 000000000..aaddb26bd
--- /dev/null
+++ b/test/factories/config_template.rb
@@ -0,0 +1,24 @@
+FactoryGirl.define do
+  factory :config_template do
+    sequence(:name) { |n| "config_template#{n}" }
+    sequence(:template) { |n| "template content #{n}" }
+
+    template_kind
+  end
+
+  factory :template_combination do
+    config_template
+    hostgroup
+    environment
+  end
+
+  factory :os_default_template do
+    config_template
+    operatingsystem
+    template_kind
+  end
+
+  factory :template_kind do
+    sequence(:name) { |n| "template_kind_#{n}" }
+  end
+end
diff --git a/test/factories/operatingsystem.rb b/test/factories/operatingsystem.rb
new file mode 100644
index 000000000..f01388714
--- /dev/null
+++ b/test/factories/operatingsystem.rb
@@ -0,0 +1,6 @@
+FactoryGirl.define do
+  factory :operatingsystem do
+    sequence(:name) { |n| "operatingsystem#{n}" }
+    sequence(:major) { |n| n }
+  end
+end
diff --git a/test/unit/config_template_test.rb b/test/unit/config_template_test.rb
index c4861be29..15248d2e9 100644
--- a/test/unit/config_template_test.rb
+++ b/test/unit/config_template_test.rb
@@ -64,4 +64,82 @@ class ConfigTemplateTest < ActiveSupport::TestCase
     assert !tmplt.save
   end
 
+  describe "Association cascading" do
+    setup do
+      @os1 = FactoryGirl.create(:operatingsystem)
+      @hg1 = FactoryGirl.create(:hostgroup)
+      @hg2 = FactoryGirl.create(:hostgroup)
+      @hg3 = FactoryGirl.create(:hostgroup)
+      @ev1 = FactoryGirl.create(:environment)
+      @ev2 = FactoryGirl.create(:environment)
+      @ev3 = FactoryGirl.create(:environment)
+
+      @tk = FactoryGirl.create(:template_kind)
+
+      # Most specific template association
+      @ct1 = FactoryGirl.create(:config_template, :template_kind => @tk, :operatingsystems => [@os1])
+      @ct1.template_combinations.create(:hostgroup => @hg1, :environment => @ev1)
+
+      # HG only
+      # We add an association on HG2/EV2 to ensure that we're not just blindly
+      # selecting all template_combinations where environment_id => nil
+      @ct2 = FactoryGirl.create(:config_template, :template_kind => @tk, :operatingsystems => [@os1])
+      @ct2.template_combinations.create(:hostgroup => @hg1, :environment => nil)
+      @ct2.template_combinations.create(:hostgroup => @hg2, :environment => @ev2)
+
+      # Env only
+      # We add an association on HG2/EV2 to ensure that we're not just blindly
+      # selecting all template_combinations where hostgroup_id => nil
+      @ct3 = FactoryGirl.create(:config_template, :template_kind => @tk, :operatingsystems => [@os1])
+      @ct3.template_combinations.create(:hostgroup => nil, :environment => @ev1)
+      @ct3.template_combinations.create(:hostgroup => @hg2, :environment => @ev2)
+
+      # Default template for the OS
+      @ctd = FactoryGirl.create(:config_template, :template_kind => @tk, :operatingsystems => [@os1])
+      @ctd.os_default_templates.create(:operatingsystem => @os1,
+                                      :template_kind_id => @ctd.template_kind_id)
+    end
+
+    test "find_template finds a matching template with hg and env" do
+      assert_equal @ct1.name,
+        ConfigTemplate.find_template({:kind => @tk.name,
+                                      :operatingsystem_id => @os1.id,
+                                      :hostgroup_id => @hg1.id,
+                                      :environment_id => @ev1.id}).name
+    end
+    test "find_template finds a matching template with hg only" do
+      assert_equal @ct2.name,
+        ConfigTemplate.find_template({:kind => @tk.name,
+                                      :operatingsystem_id => @os1.id,
+                                      :hostgroup_id => @hg1.id}).name
+    end
+    test "find_template finds a matching template with hg and mismatched env" do
+      assert_equal @ct2.name,
+        ConfigTemplate.find_template({:kind => @tk.name,
+                                      :operatingsystem_id => @os1.id,
+                                      :hostgroup_id => @hg1.id,
+                                      :environment_id => @ev3.id}).name
+    end
+    test "find_template finds a matching template with env only" do
+      assert_equal @ct3.name,
+        ConfigTemplate.find_template({:kind => @tk.name,
+                                      :operatingsystem_id => @os1.id,
+                                      :environment_id => @ev1.id}).name
+    end
+    test "find_template finds a matching template with env and mismatched hg" do
+      assert_equal @ct3.name,
+        ConfigTemplate.find_template({:kind => @tk.name,
+                                      :operatingsystem_id => @os1.id,
+                                      :hostgroup_id => @hg3.id,
+                                      :environment_id => @ev1.id}).name
+    end
+    test "find_template finds the default template when hg and env do not match" do
+      assert_equal @ctd.name,
+        ConfigTemplate.find_template({:kind => @tk.name,
+                                      :operatingsystem_id => @os1.id,
+                                      :hostgroup_id => @hg3.id,
+                                      :environment_id => @ev3.id}).name
+    end
+  end
+
 end
