# encoding: utf-8
require 'spec_helper'

require_db 'db_layer'
require_db 'grid'
require_worker 'instance_worker'

describe 'Filesystem' do

  silence_alerts
  enable_license
  evidence_no_conflict

  let(:operation) { factory_create(:operation) }

  let(:target) { factory_create(:target, operation: operation) }

  let(:agent) { factory_create(:agent, target: target) }

  def process_evidence(type, content: nil, header: nil)
    factory_create(:worker_evidence, agent: agent, type: type, content: content, header: header)
    RCS::Worker::InstanceWorker.new(agent.instance, agent.ident).run(blocking: false)
  end

  def create_filesystem_evidence(fs)
    factory_create(:evidence, agent: agent, type: 'filesystem', data: {fs: fs.to_json})
  end

  let(:find_filesystem_evidence) { ::Evidence.target(target).where(type: 'filesystem') }

  let(:fs) do
    evidence = find_filesystem_evidence.first
    fs = JSON.parse(evidence.data['fs'])
  end

  before do
    module RCS::FilesystemEvidenceMixin
      def dr; 1401180182; end
      def da; 1401180001; end
    end
  end

  context 'when a filesystem evidence is processed' do

    before do
      process_evidence('filesystem', content: [{path: '/', attr: 1}, {path: '/usr', attr: 1}, {path: '/usr/.file', attr: 0, size: 13}])
    end

    it 'creates filesystem evidence' do
      expect(fs).to eq(
        "/"=>{"d"=>1401180182, "a"=>1401180001, "c"=>
          {"usr"=>{"d"=>1401180182, "a"=>1401180001, "c"=>
            {".file"=>{"d"=>1401180182, "a"=>1401180001, "s"=>13}}
          }}
        }
      )
    end
  end

  context 'given an existing filesystem tree' do
    before do
      create_filesystem_evidence(
        "/"=>{"d"=>1401180182, "a"=>1401180001, "c"=>{
          "var"=>{"d"=>1401180182, "a"=>1401180001, "c"=>{
          }},
          "usr"=>{"d"=>1401180182, "a"=>1401180001, "c"=>{
            ".file"=>{"d"=>1401180182, "a"=>1401180001, "s"=>15},
            "f1"=>{"d"=>1401180182, "a"=>1401180001, "c"=>{}},
            "f2"=>{"d"=>1401180182, "a"=>1401180001, "c"=>{}},
            "f3"=>{"d"=>1401180182, "a"=>1401180001, "c"=>{
              ".file3"=>{"d"=>1401180182, "a"=>1401180001, "s"=>18}
            }},
            "f4"=>{"d"=>1401180182, "a"=>1401180001, "c"=>{
              ".file4"=>{"d"=>1401180182, "a"=>1401180001, "s"=>21}
            }},
          }}
        }}
      )
    end

    context 'when a fileopen evidence is processed' do
      before do
        process_evidence('fileopen', content: {path: '/usr/.file', size: 21})
      end

      it 'does not create another filesystem evidence' do
        expect(find_filesystem_evidence.count).to eq(1)
      end

      it 'updates the filesize' do
        expect(fs['/']['c']['usr']['c']['.file']['s']).to eq(21)
      end
    end

    context 'when a filesystem evidence arrives' do
      before do
        module RCS::FilesystemEvidenceMixin
          def dr; 1401180999; end
        end
      end

      before do
        process_evidence('filesystem', content: [
          {path: '/usr/info.h', attr: 0, size: 14},
          {path: '/usr/f2', attr: 3},
          {path: '/usr/f4', attr: 1},
          {path: '/usr/mails', attr: 1},
          {path: '/usr/mails/.lol', attr: 0, size: 123},
          # {path: '/usr', attr: 1},
        ])
      end

      it 'purges the old one' do
        expect(fs['/']['d']).to eq(1401180182)
        expect(fs['/']['a']).to eq(1401180001)

        expect(fs['/']['c']['usr']).to eq(
          "d"=>1401180182, "a"=>1401180001, "c"=>{
            "info.h"=>{"d"=>1401180999, "a"=>1401180001, "s"=>14},
            "f2"=>{"d"=>1401180999, "a"=>1401180001, "c"=>{}, "e"=>1},
            "mails"=>{"d"=>1401180999, "a"=>1401180001, "c"=>{
              ".lol"=>{"d"=>1401180999, "a"=>1401180001, "s"=>123}
            }},
            "f4"=>{"d"=>1401180999, "a"=>1401180001, "c"=>{
              ".file4"=>{"d"=>1401180182, "a"=>1401180001, "s"=>21}
            }},
          }
        )
      end
    end
  end

  context 'when a fileopen evidence is processed' do
    before do
      process_evidence('fileopen', content: {path: '/usr/.file', size: 25})
    end

    it 'creates filesystem evidence' do
      expect(fs['/']['c']['usr']['c']['.file']).to eq("d"=>1401180182, "a"=>1401180001, "s"=>25)
    end
  end

  context 'when a fileopen evidence (windows paths) is processed' do
    before do
      process_evidence('fileopen', content: {path: "C:\\Program Data\\file.exe", size: 21})
    end

    it 'creates filesystem evidence' do
      expect(fs['C:']['c']['Program Data']['c']['file.exe']).to eq("d"=>1401180182, "a"=>1401180001, "s"=>21)
    end
  end

  context 'when a filecap evidence is processed' do
    before do
      process_evidence('filecap', header: {path: '/usr/var/README'}, content: 'foobar')
    end

    it 'creates filesystem evidence' do
      expect(fs['/']['c']['usr']['c']['var']['c']['README']).to eq("d"=>1401180182, "a"=>1401180001, "s"=>6)
    end
  end
end
