



module Buildwise
  class App
    module TestFilesHelper



      





      def get_test_file_path_on_server(project, filename) 
        
        test_file_path = nil
        if (project.config.ui_tests_local_working_dir && Dir.exist?(project.config.ui_tests_local_working_dir) )
          test_file_path = File.join(project.config.ui_tests_local_working_dir, filename)
        end
    
        current_dir = File.expand_path(".")
        scm_output = nil

        if !File.exist?(test_file_path)
          puts("[INFO] #{test_file_path} not exists, try get from version control, used the one under .buildwise/sources" )
          begin
            FileUtils.chdir(File.join(project.working_dir, "sources"))
            scm_cmd = "git pull"
            scm_output = `#{scm_cmd}`
          rescue => e
            logger.warn("Failed to git pull, #{e}")
          ensure              
            FileUtils.chdir(current_dir)
          end      
          test_file_path = File.join(project.working_dir, "sources",  project.config.ui_tests_dir, filename)
        end
        return test_file_path
      end

      def execute_test_script_with_system_command(test_file_path, envs = {})
        begin          
          run_time_dir = File.expand_path File.join(Padrino.root, "runtime")
          unless File.exist?(run_time_dir)
            FileUtils.mkdir(run_time_dir)
          end
          
          test_file_ext = File.extname(test_file_path).downcase rescue nil
          framework_cmd = "rspec" # default to Rspec
          if ".js"  == test_file_ext || test_file_path.end_with?(".js")
            framework_cmd = "mocha"
          elsif ".py"  == test_file_ext || test_file_path.end_with?(".py")
            framework_cmd = "pytest"
          end
          
          if framework_cmd == "rspec"
            
            load_env_rb = File.join(run_time_dir, "load_env_#{Time.now.strftime('%y%m%d%H%M%S')}.rb")
            fio = File.open(load_env_rb, "w")
          
            envs.each do |key, val|
              if val.class == Array
                fio.puts('ENV["'+ key + '"]="'+ val.join(",")+ '";')
              else   
                fio.puts('ENV["'+ key + '"]="'+ val.to_s + '";')
              end

            end
            fio.flush
            fio.close
          
            cmd = "rspec --require #{load_env_rb} #{test_file_path}"
          else
            cmd = "#{framework_cmd} #{test_file_path}"            
          end
          

          cmd_output = `#{cmd}`
          return cmd_output
        rescue => e
          logger.warn("Failed to run test with command: #{cmd}, #{e}")      
        end
      end
      
      
      def execute_test_script_childprocess(test_file_path, envs = {})
        result_output = ""
        
        test_file_ext = File.extname(test_file_path).downcase rescue nil
        framework_cmd = "rspec" # default to Rspec
        if ".js"  == test_file_ext || test_file_path.end_with?(".js")
          framework_cmd = "mocha"
        elsif ".py"  == test_file_ext || test_file_path.end_with?(".py")
          framework_cmd = "pytest"
        end
        
        begin          

          process = ChildProcess.build(framework_cmd, test_file_path)
          process.io.inherit!


          temp_file =  Tempfile.new("child-output")
          process.io.stdout = temp_file

          envs.each do |key, val|
            process.environment[key] = val                         
          end
          
          process.start
        


          begin
            process.poll_for_exit(10 * 60) # 10 minutes
          rescue ChildProcess::TimeoutError
            process.stop # tries increasingly harsher methods to kill the process.
          end
        
          temp_file.rewind
          result_output = temp_file.read
          temp_file.close
          
        rescue => e
          logger.warn("Failed to run test with with child process: #{cmd}, #{e}")      
        end
        

        result_output = result_output.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
        return result_output
      end
      
      
      def execute_individual_test_case_with_system_command(test_file_path, test_case_name, test_case_start_line, envs = {})
        begin          
          run_time_dir = File.expand_path File.join(Padrino.root, "runtime")
          unless File.exist?(run_time_dir)
            FileUtils.mkdir(run_time_dir)
          end
          
          load_env_rb = File.join(run_time_dir, "load_env_#{Time.now.strftime('%y%m%d%H%M%S')}.rb")
          fio = File.open(load_env_rb, "w")
          
          envs.each do |key, val|
            if val.class == Array
              fio.puts('ENV["'+ key + '"]="'+ val.join(",")+ '";')
            else   
              fio.puts('ENV["'+ key + '"]="'+ val.to_s + '";')
            end

          end
          fio.flush
          fio.close
          
          test_case_file_line = test_case_start_line.strip.empty? ? test_file_path : test_file_path + ":" + test_case_start_line
          cmd = "rspec --require #{load_env_rb} #{test_case_file_line}"
          logger.debug("\n[DEBUG] run test command = #{cmd}")

          cmd_output = `#{cmd}`
          return cmd_output
        rescue => e
          logger.warn("Failed to run test with command: #{cmd}, #{e}")      
        end
      end
  
      def execute_individual_test_case_childprocess(test_file_path, test_case_name, test_case_start_line, envs = {})
  



        
        test_case_file_line = test_case_start_line.strip.empty? ? test_file_path : test_file_path + ":" + test_case_start_line
        
        test_file_ext = File.extname(test_file_path).downcase rescue nil
        framework_cmd = "rspec" # default to Rspec
        if ".js"  == test_file_ext
          framework_cmd = "mocha"
        elsif ".py"  == test_file_ext
          framework_cmd = "pytest"
        end
        
        process = ChildProcess.build(framework_cmd, test_case_file_line)
        process.detach = false  
        temp_file =  Tempfile.new("child-output")     
        process.io.stdout = temp_file
        process.io.stderr = temp_file

        envs.each do |key, val|
          process.environment[key] = val                         
        end
                




        process.start
        
        begin
          process.poll_for_exit(10 * 60) # 10 minutes
        rescue ChildProcess::TimeoutError
          process.stop # tries increasingly harsher methods to kill the process.
        end
        
        return File.read(temp_file)
      end
      
      
      def execute_test_script(test_file_path, envs = {})
        logger.info("Executing test script |#{test_file_path}|")
        if RUBY_PLATFORM =~ /mingw/
          execute_test_script_with_system_command(test_file_path, envs)
        else
          execute_test_script_childprocess(test_file_path, envs)
        end
      end
    
      def execute_individual_test_case(test_file_path, test_case_name, envs = {})

        logger.info("Executing test case in |#{test_file_path}|")
        spec_file = SpecFile.new(test_file_path)        
        opts = {:test_file_path => test_file_path, :test_case_name => test_case_name}
        spec_behaviour = spec_file.behaviour_lookups[test_case_name]
        spec_behaviour ||= spec_file.behaviour_lookups['"' + test_case_name + '"']
        
        test_case_start_line = nil
        if spec_behaviour && spec_behaviour.start_line
          test_case_start_line =  spec_behaviour.start_line.to_s
        end 
        


        if test_case_start_line        
          if RUBY_PLATFORM =~ /mingw/
            execute_individual_test_case_with_system_command(test_file_path, test_case_name, test_case_start_line, envs)
          else
            execute_individual_test_case_childprocess(test_file_path, test_case_name, test_case_start_line, envs)
          end
        end
        
      end
  
  
    end

    helpers TestFilesHelper
  end
end