<commit_before>require 'rack_helper'
require_app 'api/v1'

describe 'API routes/cameras' do

  let(:app) { Evercam::APIv1 }

  let(:camera) { create(:camera, is_public: true) }

  let(:token) { create(:access_token) }

  let(:access_right) { create(:access_right, token: token) }

  describe 'presented fields' do

    describe "for public cameras" do
      describe "when not the camera owner" do

        let(:json) {
          output = get("/cameras/#{camera.exid}").json
          output['cameras'] ? output['cameras'][0] : {}
        }

        it 'returns a subset the cameras details' do
          expect(json).to have_keys(
            'id', 'name', 'created_at', 'updated_at', 'last_polled_at',
            'is_public', 'is_online', 'last_online_at', 'vendor', 'model',
            'timezone', 'location')
          expect(json).to not_have_keys('owner', 'endpoints', 'snapshots',
                                        'auth', 'mac_address')
        end

      end

      describe "when queried by the camera owner" do
        let(:user) { create(:user, username: 'xxxx', password: '<PASSWORD>') }
        let(:camera) { create(:camera, is_public: true, owner: user) }
        let(:json) {
          env    = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
          output = get("/cameras/#{camera.exid}", {}, env).json
          output['cameras'] ? output['cameras'][0] : {}
        }

        it 'returns the full camera details' do
          expect(json).to have_keys(
            'id', 'name', 'owner', 'created_at', 'updated_at',
            'last_polled_at', 'is_public', 'is_online', 'last_online_at',
            'endpoints', 'vendor', 'model', 'timezone', 'snapshots', 'auth',
            'location', 'mac_address')
        end
      end

      describe "when queried by someone that is not the camera owner" do
        let(:user1) { create(:user, username: 'aaaa', password: '<PASSWORD>') }
        let(:user2) { create(:user, username: 'xxxx', password: '<PASSWORD>') }
        let(:camera) { create(:camera, is_public: true, owner: user2) }
        let(:json) {
          user1.save
          user2.save
          env    = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('aaaa:bbbb')}" }
          output = get("/cameras/#{camera.exid}", {}, env).json
          output['cameras'] ? output['cameras'][0] : {}
        }

        it 'returns s subset of the cameras details' do
          expect(json).to have_keys(
            'id', 'name', 'created_at', 'updated_at', 'last_polled_at',
            'is_public', 'is_online', 'last_online_at', 'vendor', 'model',
            'timezone', 'location')
          expect(json).to not_have_keys('owner', 'endpoints', 'snapshots',
                                        'auth', 'mac_address')
        end
      end
    end

    describe "when location"

      let(:json) {
        output = get("/cameras/#{camera.exid}").json
        output['cameras'] ? output['cameras'][0] : {}
      }

      context 'is nil' do
        it 'returns location as nil' do
          camera.update(location: nil)
          expect(json['location']).to be_nil
        end
      end

      context 'is not nil' do
        it 'returns location as lng lat object' do
          camera.update(location: { lng: 10, lat: 20 })
          expect(json['location']).to have_keys('lng', 'lat')
        end
      end

  end

  describe 'GET /cameras/:id' do

    context 'when the camera does not exist' do
      it 'returns a NOT FOUND status' do
        expect(get('/cameras/xxxx').status).to eq(404)
      end
    end

    context 'when the camera is public' do
      it 'returns the camera data' do
        response = get("/cameras/#{camera.exid}")
        expect(response.status).to eq(200)
      end
    end

    context 'when the camera is private' do

      let(:camera) { create(:camera, is_public: false) }

      context 'when the request is unauthenticated' do
        it 'returns an UNAUTHORIZED status' do
          expect(get("/cameras/#{camera.exid}").status).to eq(401)
        end
      end

      context 'when the request is unauthorized' do
        it 'returns a FORBIDDEN status' do
          create(:user, username: 'xxxx', password: '<PASSWORD>')
          env = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
          expect(get("/cameras/#{camera.exid}", {}, env).status).to eq(403)
        end
      end

      context 'when the request is authorized' do
        it 'returns the camera data' do
          camera.update(owner: create(:user, username: 'xxxx', password: '<PASSWORD>'))
          env = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
          expect(get("/cameras/#{camera.exid}", {}, env).status).to eq(200)
        end
      end

    end

    it 'returns the camera make and model information when available' do
      model = create(:firmware)
      camera.update(firmware: model)

      response = get("/cameras/#{camera.exid}")
      data = response.json['cameras'][0]

      expect(data['vendor']).to eq(model.vendor.exid)
      expect(data['model']).to eq(model.name)
    end

    it 'can fetch details for a camera via MAC address' do
      camera.update(owner: create(:user, username: 'xxxx', password: '<PASSWORD>'))
      env = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
      response = get("/cameras/#{camera.mac_address}", {}, env)
      data     = response.json['cameras'][0]

      expect(data['id']).to eq(camera.exid)
      expect(data['mac_address']).to eq(camera.mac_address)
    end

  end

  describe 'POST /cameras' do

    let(:auth) { env_for(session: { user: create(:user).id }) }

    let(:params) {
      {
        id: 'my-new-camera',
        name: "Garrett's Super New Camera",
        endpoints: ['http://localhost:1234'],
        is_public: true
      }.merge(
        build(:camera).config
      )
    }

    context 'when the params are valid' do

      before(:each) do
        post('/cameras', params, auth)
      end

      it 'returns a CREATED status' do
        expect(last_response.status).to eq(201)
      end

      it 'creates a new camera in the system' do
        expect(Camera.first.exid).
          to eq(params[:id])
      end

      it 'returns the new camera' do
        expect(last_response.json['cameras'].map{ |s| s['id'] }).
          to eq([Camera.first.exid])
      end

    end

    context 'when required keys are missing' do
      it 'returns a BAD REQUEST status' do
        post('/cameras', { id: '' }, auth)
        expect(last_response.status).to eq(400)
      end
    end

    context 'when is_public is null' do
      it 'returns a BAD REQUEST status' do
        post('/cameras', params.merge(is_public: nil), auth)
        expect(last_response.status).to eq(400)
      end
    end

    context 'when :endpoints key is missing' do
      it 'returns a BAD REQUEST status' do
        post('/cameras', params.merge(endpoints: nil), auth)
        expect(last_response.status).to eq(400)
      end
    end

    context 'when no authentication is provided' do
      it 'returns an UNAUTHROZIED status' do
        expect(post('/cameras', params).status).to eq(401)
      end
    end

  end

  describe 'PATCH /cameras' do

    #let(:camera) { create(:camera, is_public: true, owner: create(:user, username: 'xxxx', password: '<PASSWORD>')) }
    let(:camera) { create(:camera, is_public: false, owner: create(:user, username: 'xxxx', password: '<PASSWORD>')) }
    let(:model) { create(:firmware) }

    let(:params) {
      {
        name: "Garrett's Super New Camera v2",
        endpoints: ['http://www.evercam.io', 'http://localhost:4321'],
        is_public: false,
        mac_address: 'aa:aa:aa:aa:aa:aa',
        vendor: model.vendor.exid,
        model: model.name,
        timezone: 'Etc/GMT+1',
        snapshots: { 'jpg' => '/snap'},
        auth: { 'basic' => {'username' => 'zzz', 'password' => '<PASSWORD>'}}
      }
    }

    context 'when the params are valid' do

      before do
        camera.add_endpoint({
          scheme: 'http',
          host: 'www.evercam.io',
          port: 80
        })
        auth = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
        patch("/cameras/#{camera.exid}", params, auth)
      end

      it 'returns a OK status' do
        expect(last_response.status).to eq(200)
      end

      it 'updates camera in the system' do
        cam = Camera.by_exid(camera.exid)
        expect(cam.is_public).to eq(false)
        expect(cam.name).to eq("Garrett's Super New Camera v2")
        expect(cam.firmware).to eq(model)
        expect(cam.mac_address).to eq('aa:aa:aa:aa:aa:aa')
        expect(cam.timezone.zone).to eq('Etc/GMT+1')
        expect(cam.config['snapshots']).to eq({ 'jpg' => '/snap'})
        expect(cam.config['auth']).to eq({ 'basic' => {'username' => 'zzz', 'password' => '<PASSWORD>'}})
        expect(cam.endpoints.length).to eq(2)
        expect(cam.endpoints[1][:port]).to eq(4321)
      end

      it 'returns the updated camera' do
        expect(last_response.json['cameras'].map{ |s| s['id'] }).
          to eq([camera.exid])
      end

    end

    context 'when params are empty' do
      it 'returns a OK status' do
        auth = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
        patch("/cameras/#{camera.exid}", params.clear, auth)
        expect(last_response.status).to eq(200)
      end
    end

    context 'when no authentication is provided' do
      it 'returns an UNAUTHROZIED status' do
        expect(patch("/cameras/#{camera.exid}", params).status).to eq(401)
      end
    end

  end

  describe 'DELETE /cameras' do

    let(:camera) { create(:camera, is_public: false, owner: create(:user, username: 'xxxx', password: '<PASSWORD>')) }

    context 'when params are empty' do
      it 'returns a OK status' do
        auth = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
        delete("/cameras/#{camera.exid}", {}, auth)
        expect(last_response.status).to eq(200)
        expect(Camera.by_exid(camera.exid)).to eq(nil)
      end
    end

    context 'when no authentication is provided' do
      it 'returns an UNAUTHROZIED status' do
        expect(delete("/cameras/#{camera.exid}", {}).status).to eq(401)
      end
    end

  end

end

<commit_msg>Check for slash in snapshots config - test<commit_after>require 'rack_helper'
require_app 'api/v1'

describe 'API routes/cameras' do

  let(:app) { Evercam::APIv1 }

  let(:camera) { create(:camera, is_public: true) }

  let(:token) { create(:access_token) }

  let(:access_right) { create(:access_right, token: token) }

  describe 'presented fields' do

    describe "for public cameras" do
      describe "when not the camera owner" do

        let(:json) {
          output = get("/cameras/#{camera.exid}").json
          output['cameras'] ? output['cameras'][0] : {}
        }

        it 'returns a subset the cameras details' do
          expect(json).to have_keys(
            'id', 'name', 'created_at', 'updated_at', 'last_polled_at',
            'is_public', 'is_online', 'last_online_at', 'vendor', 'model',
            'timezone', 'location')
          expect(json).to not_have_keys('owner', 'endpoints', 'snapshots',
                                        'auth', 'mac_address')
        end

      end

      describe "when queried by the camera owner" do
        let(:user) { create(:user, username: 'xxxx', password: '<PASSWORD>') }
        let(:camera) { create(:camera, is_public: true, owner: user) }
        let(:json) {
          env    = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
          output = get("/cameras/#{camera.exid}", {}, env).json
          output['cameras'] ? output['cameras'][0] : {}
        }

        it 'returns the full camera details' do
          expect(json).to have_keys(
            'id', 'name', 'owner', 'created_at', 'updated_at',
            'last_polled_at', 'is_public', 'is_online', 'last_online_at',
            'endpoints', 'vendor', 'model', 'timezone', 'snapshots', 'auth',
            'location', 'mac_address')
        end
      end

      describe "when queried by someone that is not the camera owner" do
        let(:user1) { create(:user, username: 'aaaa', password: '<PASSWORD>') }
        let(:user2) { create(:user, username: 'xxxx', password: '<PASSWORD>') }
        let(:camera) { create(:camera, is_public: true, owner: user2) }
        let(:json) {
          user1.save
          user2.save
          env    = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('aaaa:bbbb')}" }
          output = get("/cameras/#{camera.exid}", {}, env).json
          output['cameras'] ? output['cameras'][0] : {}
        }

        it 'returns s subset of the cameras details' do
          expect(json).to have_keys(
            'id', 'name', 'created_at', 'updated_at', 'last_polled_at',
            'is_public', 'is_online', 'last_online_at', 'vendor', 'model',
            'timezone', 'location')
          expect(json).to not_have_keys('owner', 'endpoints', 'snapshots',
                                        'auth', 'mac_address')
        end
      end
    end

    describe "when location"

      let(:json) {
        output = get("/cameras/#{camera.exid}").json
        output['cameras'] ? output['cameras'][0] : {}
      }

      context 'is nil' do
        it 'returns location as nil' do
          camera.update(location: nil)
          expect(json['location']).to be_nil
        end
      end

      context 'is not nil' do
        it 'returns location as lng lat object' do
          camera.update(location: { lng: 10, lat: 20 })
          expect(json['location']).to have_keys('lng', 'lat')
        end
      end

  end

  describe 'GET /cameras/:id' do

    context 'when the camera does not exist' do
      it 'returns a NOT FOUND status' do
        expect(get('/cameras/xxxx').status).to eq(404)
      end
    end

    context 'when the camera is public' do
      it 'returns the camera data' do
        response = get("/cameras/#{camera.exid}")
        expect(response.status).to eq(200)
      end
    end

    context 'when the camera is private' do

      let(:camera) { create(:camera, is_public: false) }

      context 'when the request is unauthenticated' do
        it 'returns an UNAUTHORIZED status' do
          expect(get("/cameras/#{camera.exid}").status).to eq(401)
        end
      end

      context 'when the request is unauthorized' do
        it 'returns a FORBIDDEN status' do
          create(:user, username: 'xxxx', password: '<PASSWORD>')
          env = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
          expect(get("/cameras/#{camera.exid}", {}, env).status).to eq(403)
        end
      end

      context 'when the request is authorized' do
        it 'returns the camera data' do
          camera.update(owner: create(:user, username: 'xxxx', password: '<PASSWORD>'))
          env = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
          expect(get("/cameras/#{camera.exid}", {}, env).status).to eq(200)
        end
      end

    end

    it 'returns the camera make and model information when available' do
      model = create(:firmware)
      camera.update(firmware: model)

      response = get("/cameras/#{camera.exid}")
      data = response.json['cameras'][0]

      expect(data['vendor']).to eq(model.vendor.exid)
      expect(data['model']).to eq(model.name)
    end

    it 'can fetch details for a camera via MAC address' do
      camera.update(owner: create(:user, username: 'xxxx', password: '<PASSWORD>'))
      env = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
      response = get("/cameras/#{camera.mac_address}", {}, env)
      data     = response.json['cameras'][0]

      expect(data['id']).to eq(camera.exid)
      expect(data['mac_address']).to eq(camera.mac_address)
    end

  end

  describe 'POST /cameras' do

    let(:auth) { env_for(session: { user: create(:user).id }) }

    let(:params) {
      {
        id: 'my-new-camera',
        name: "Garrett's Super New Camera",
        endpoints: ['http://localhost:1234'],
        is_public: true
      }.merge(
        build(:camera).config
      )
    }

    context 'when the params are valid' do

      before(:each) do
        post('/cameras', params, auth)
      end

      it 'returns a CREATED status' do
        expect(last_response.status).to eq(201)
      end

      it 'creates a new camera in the system' do
        expect(Camera.first.exid).
          to eq(params[:id])
      end

      it 'returns the new camera' do
        expect(last_response.json['cameras'].map{ |s| s['id'] }).
          to eq([Camera.first.exid])
      end

    end

    context 'when required keys are missing' do
      it 'returns a BAD REQUEST status' do
        post('/cameras', { id: '' }, auth)
        expect(last_response.status).to eq(400)
      end
    end

    context 'when is_public is null' do
      it 'returns a BAD REQUEST status' do
        post('/cameras', params.merge(is_public: nil), auth)
        expect(last_response.status).to eq(400)
      end
    end

    context 'when :endpoints key is missing' do
      it 'returns a BAD REQUEST status' do
        post('/cameras', params.merge(endpoints: nil), auth)
        expect(last_response.status).to eq(400)
      end
    end

    context 'when no authentication is provided' do
      it 'returns an UNAUTHROZIED status' do
        expect(post('/cameras', params).status).to eq(401)
      end
    end

  end

  describe 'PATCH /cameras' do

    #let(:camera) { create(:camera, is_public: true, owner: create(:user, username: 'xxxx', password: '<PASSWORD>')) }
    let(:camera) { create(:camera, is_public: false, owner: create(:user, username: 'xxxx', password: '<PASSWORD>')) }
    let(:model) { create(:firmware) }

    let(:params) {
      {
        name: "Garrett's Super New Camera v2",
        endpoints: ['http://www.evercam.io', 'http://localhost:4321'],
        is_public: false,
        mac_address: 'aa:aa:aa:aa:aa:aa',
        vendor: model.vendor.exid,
        model: model.name,
        timezone: 'Etc/GMT+1',
        snapshots: { 'jpg' => '/snap'},
        auth: { 'basic' => {'username' => 'zzz', 'password' => '<PASSWORD>'}}
      }
    }

    context 'when the params are valid' do

      before do
        camera.add_endpoint({
          scheme: 'http',
          host: 'www.evercam.io',
          port: 80
        })
        auth = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
        patch("/cameras/#{camera.exid}", params, auth)
      end

      it 'returns a OK status' do
        expect(last_response.status).to eq(200)
      end

      it 'updates camera in the system' do
        cam = Camera.by_exid(camera.exid)
        expect(cam.is_public).to eq(false)
        expect(cam.name).to eq("Garrett's Super New Camera v2")
        expect(cam.firmware).to eq(model)
        expect(cam.mac_address).to eq('aa:aa:aa:aa:aa:aa')
        expect(cam.timezone.zone).to eq('Etc/GMT+1')
        expect(cam.config['snapshots']).to eq({ 'jpg' => '/snap'})
        expect(cam.config['auth']).to eq({ 'basic' => {'username' => 'zzz', 'password' => '<PASSWORD>'}})
        expect(cam.endpoints.length).to eq(2)
        expect(cam.endpoints[1][:port]).to eq(4321)
      end

      it 'returns the updated camera' do
        expect(last_response.json['cameras'].map{ |s| s['id'] }).
          to eq([camera.exid])
      end

    end

    context 'when params are empty' do
      it 'returns a OK status' do
        auth = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
        patch("/cameras/#{camera.exid}", params.clear, auth)
        expect(last_response.status).to eq(200)
      end
    end

    context 'when snapshot url doesnt start with slash' do
      it 'returns a OK status' do
        auth = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
        patch("/cameras/#{camera.exid}", {snapshots: {jpg: 'image.jpg'}}, auth)
        expect(last_response.json['cameras'][0]['snapshots']['jpg']).to eq('/image.jpg')
        expect(last_response.status).to eq(200)
      end
    end

    context 'when no authentication is provided' do
      it 'returns an UNAUTHROZIED status' do
        expect(patch("/cameras/#{camera.exid}", params).status).to eq(401)
      end
    end

  end

  describe 'DELETE /cameras' do

    let(:camera) { create(:camera, is_public: false, owner: create(:user, username: 'xxxx', password: '<PASSWORD>')) }

    context 'when params are empty' do
      it 'returns a OK status' do
        auth = { 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('xxxx:yyyy')}" }
        delete("/cameras/#{camera.exid}", {}, auth)
        expect(last_response.status).to eq(200)
        expect(Camera.by_exid(camera.exid)).to eq(nil)
      end
    end

    context 'when no authentication is provided' do
      it 'returns an UNAUTHROZIED status' do
        expect(delete("/cameras/#{camera.exid}", {}).status).to eq(401)
      end
    end

  end

end


{'fraction_non_alphanumeric': 0.15061295971978983, 'fraction_numerical': 0.011170540067212572, 'mean_word_length': 2.4337721436697546, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 58, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '664953', 'n_tokens_mistral': 6914, 'n_tokens_neox': 6520, 'n_words': 1688}