gitlab-mail_room 0.0.4 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitlab/issue_templates/Default.md +9 -0
- data/.gitlab/issue_templates/Release.md +8 -0
- data/.gitlab-ci.yml +18 -16
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +494 -0
- data/.ruby-version +1 -1
- data/.travis.yml +12 -5
- data/CHANGELOG.md +4 -0
- data/CONTRIBUTING.md +40 -0
- data/README.md +136 -10
- data/Rakefile +1 -1
- data/lib/mail_room/arbitration/redis.rb +1 -1
- data/lib/mail_room/cli.rb +2 -2
- data/lib/mail_room/configuration.rb +11 -1
- data/lib/mail_room/connection.rb +10 -177
- data/lib/mail_room/coordinator.rb +8 -4
- data/lib/mail_room/crash_handler.rb +8 -12
- data/lib/mail_room/delivery/letter_opener.rb +1 -1
- data/lib/mail_room/delivery/postback.rb +36 -4
- data/lib/mail_room/delivery/sidekiq.rb +4 -3
- data/lib/mail_room/health_check.rb +60 -0
- data/lib/mail_room/imap/connection.rb +200 -0
- data/lib/mail_room/imap/message.rb +19 -0
- data/lib/mail_room/imap.rb +8 -0
- data/lib/mail_room/jwt.rb +39 -0
- data/lib/mail_room/logger/structured.rb +15 -1
- data/lib/mail_room/mailbox.rb +62 -20
- data/lib/mail_room/mailbox_watcher.rb +15 -2
- data/lib/mail_room/message.rb +16 -0
- data/lib/mail_room/microsoft_graph/connection.rb +243 -0
- data/lib/mail_room/microsoft_graph.rb +7 -0
- data/lib/mail_room/version.rb +2 -2
- data/lib/mail_room.rb +2 -0
- data/mail_room.gemspec +13 -4
- data/spec/fixtures/jwt_secret +1 -0
- data/spec/fixtures/test_config.yml +3 -0
- data/spec/lib/arbitration/redis_spec.rb +9 -7
- data/spec/lib/cli_spec.rb +32 -17
- data/spec/lib/configuration_spec.rb +10 -3
- data/spec/lib/coordinator_spec.rb +27 -11
- data/spec/lib/crash_handler_spec.rb +10 -9
- data/spec/lib/delivery/letter_opener_spec.rb +10 -6
- data/spec/lib/delivery/logger_spec.rb +8 -10
- data/spec/lib/delivery/postback_spec.rb +73 -41
- data/spec/lib/delivery/que_spec.rb +5 -8
- data/spec/lib/delivery/sidekiq_spec.rb +33 -11
- data/spec/lib/health_check_spec.rb +57 -0
- data/spec/lib/{connection_spec.rb → imap/connection_spec.rb} +13 -17
- data/spec/lib/imap/message_spec.rb +36 -0
- data/spec/lib/jwt_spec.rb +80 -0
- data/spec/lib/logger/structured_spec.rb +34 -2
- data/spec/lib/mailbox_spec.rb +79 -34
- data/spec/lib/mailbox_watcher_spec.rb +54 -41
- data/spec/lib/message_spec.rb +35 -0
- data/spec/lib/microsoft_graph/connection_spec.rb +252 -0
- data/spec/spec_helper.rb +14 -4
- metadata +130 -21
| @@ -9,24 +9,22 @@ describe MailRoom::Delivery::Logger do | |
| 9 9 | 
             
                  it 'creates a new ruby logger' do
         | 
| 10 10 | 
             
                    ::Logger.stubs(:new)
         | 
| 11 11 |  | 
| 12 | 
            -
                     | 
| 12 | 
            +
                    ::Logger.expects(:new).with(STDOUT)
         | 
| 13 13 |  | 
| 14 | 
            -
                     | 
| 14 | 
            +
                    MailRoom::Delivery::Logger.new(mailbox)
         | 
| 15 15 | 
             
                  end
         | 
| 16 16 | 
             
                end
         | 
| 17 17 |  | 
| 18 18 | 
             
                context "with a log path" do
         | 
| 19 | 
            -
                  let(:mailbox) {build_mailbox(: | 
| 19 | 
            +
                  let(:mailbox) {build_mailbox(log_path: '/var/log/mail-room.log')}
         | 
| 20 20 |  | 
| 21 21 | 
             
                  it 'creates a new file to append to' do
         | 
| 22 | 
            -
                    ::Logger.stubs(:new)
         | 
| 23 22 | 
             
                    file = stub(:sync=)
         | 
| 24 | 
            -
                    ::File.stubs(:open).returns(file)
         | 
| 25 23 |  | 
| 26 | 
            -
                     | 
| 24 | 
            +
                    File.expects(:open).with('/var/log/mail-room.log', 'a').returns(file)
         | 
| 25 | 
            +
                    ::Logger.stubs(:new).with(file)
         | 
| 27 26 |  | 
| 28 | 
            -
                     | 
| 29 | 
            -
                    expect(::Logger).to have_received(:new).with(file)
         | 
| 27 | 
            +
                    MailRoom::Delivery::Logger.new(mailbox)
         | 
| 30 28 | 
             
                  end
         | 
| 31 29 | 
             
                end
         | 
| 32 30 | 
             
              end
         | 
| @@ -38,9 +36,9 @@ describe MailRoom::Delivery::Logger do | |
| 38 36 | 
             
                  logger = stub(:info)
         | 
| 39 37 | 
             
                  ::Logger.stubs(:new).returns(logger)
         | 
| 40 38 |  | 
| 41 | 
            -
                   | 
| 39 | 
            +
                  logger.expects(:info).with('a message')
         | 
| 42 40 |  | 
| 43 | 
            -
                   | 
| 41 | 
            +
                  MailRoom::Delivery::Logger.new(mailbox).deliver('a message')
         | 
| 44 42 | 
             
                end
         | 
| 45 43 | 
             
              end
         | 
| 46 44 | 
             
            end
         | 
| @@ -5,8 +5,8 @@ describe MailRoom::Delivery::Postback do | |
| 5 5 | 
             
              describe '#deliver' do
         | 
| 6 6 | 
             
                context 'with token auth delivery' do
         | 
| 7 7 | 
             
                  let(:mailbox) {build_mailbox({
         | 
| 8 | 
            -
                    : | 
| 9 | 
            -
                    : | 
| 8 | 
            +
                    delivery_url: 'http://localhost/inbox',
         | 
| 9 | 
            +
                    delivery_token: 'abcdefg'
         | 
| 10 10 | 
             
                  })}
         | 
| 11 11 |  | 
| 12 12 | 
             
                  let(:delivery_options) {
         | 
| @@ -18,28 +18,22 @@ describe MailRoom::Delivery::Postback do | |
| 18 18 | 
             
                    request = stub
         | 
| 19 19 | 
             
                    Faraday.stubs(:new).returns(connection)
         | 
| 20 20 |  | 
| 21 | 
            -
                    connection. | 
| 22 | 
            -
                    connection. | 
| 21 | 
            +
                    connection.expects(:token_auth).with('abcdefg')
         | 
| 22 | 
            +
                    connection.expects(:post).yields(request)
         | 
| 23 23 |  | 
| 24 | 
            -
                    request. | 
| 25 | 
            -
                    request. | 
| 24 | 
            +
                    request.expects(:url).with('http://localhost/inbox')
         | 
| 25 | 
            +
                    request.expects(:body=).with('a message')
         | 
| 26 26 |  | 
| 27 27 | 
             
                    MailRoom::Delivery::Postback.new(delivery_options).deliver('a message')
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                    expect(connection).to have_received(:token_auth).with('abcdefg')
         | 
| 30 | 
            -
                    expect(connection).to have_received(:post)
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                    expect(request).to have_received(:url).with('http://localhost/inbox')
         | 
| 33 | 
            -
                    expect(request).to have_received(:body=).with('a message')
         | 
| 34 28 | 
             
                  end
         | 
| 35 29 | 
             
                end
         | 
| 36 30 |  | 
| 37 31 | 
             
                context 'with basic auth delivery options' do
         | 
| 38 32 | 
             
                  let(:mailbox) {build_mailbox({
         | 
| 39 | 
            -
                    : | 
| 40 | 
            -
                      : | 
| 41 | 
            -
                      : | 
| 42 | 
            -
                      : | 
| 33 | 
            +
                    delivery_options: {
         | 
| 34 | 
            +
                      url: 'http://localhost/inbox',
         | 
| 35 | 
            +
                      username: 'user1',
         | 
| 36 | 
            +
                      password: 'password123abc'
         | 
| 43 37 | 
             
                    }
         | 
| 44 38 | 
             
                  })}
         | 
| 45 39 |  | 
| @@ -52,56 +46,94 @@ describe MailRoom::Delivery::Postback do | |
| 52 46 | 
             
                    request = stub
         | 
| 53 47 | 
             
                    Faraday.stubs(:new).returns(connection)
         | 
| 54 48 |  | 
| 55 | 
            -
                    connection. | 
| 56 | 
            -
                    connection. | 
| 49 | 
            +
                    connection.expects(:basic_auth).with('user1', 'password123abc')
         | 
| 50 | 
            +
                    connection.expects(:post).yields(request)
         | 
| 57 51 |  | 
| 58 | 
            -
                    request. | 
| 59 | 
            -
                    request. | 
| 52 | 
            +
                    request.expects(:url).with('http://localhost/inbox')
         | 
| 53 | 
            +
                    request.expects(:body=).with('a message')
         | 
| 60 54 |  | 
| 61 55 | 
             
                    MailRoom::Delivery::Postback.new(delivery_options).deliver('a message')
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                    expect(connection).to have_received(:basic_auth).with('user1', 'password123abc')
         | 
| 64 | 
            -
                    expect(connection).to have_received(:post)
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                    expect(request).to have_received(:url).with('http://localhost/inbox')
         | 
| 67 | 
            -
                    expect(request).to have_received(:body=).with('a message')
         | 
| 68 56 | 
             
                  end
         | 
| 69 57 |  | 
| 70 58 | 
             
                  context 'with content type in the delivery options' do
         | 
| 71 59 | 
             
                    let(:mailbox) {build_mailbox({
         | 
| 72 | 
            -
                      : | 
| 73 | 
            -
                        : | 
| 74 | 
            -
                        : | 
| 75 | 
            -
                        : | 
| 76 | 
            -
                        : | 
| 60 | 
            +
                      delivery_options: {
         | 
| 61 | 
            +
                        url: 'http://localhost/inbox',
         | 
| 62 | 
            +
                        username: 'user1',
         | 
| 63 | 
            +
                        password: 'password123abc',
         | 
| 64 | 
            +
                        content_type: 'text/plain'
         | 
| 77 65 | 
             
                      }
         | 
| 78 66 | 
             
                    })}
         | 
| 79 67 |  | 
| 80 | 
            -
              
         | 
| 81 68 | 
             
                    let(:delivery_options) {
         | 
| 82 69 | 
             
                      MailRoom::Delivery::Postback::Options.new(mailbox)
         | 
| 83 70 | 
             
                    }
         | 
| 84 | 
            -
             | 
| 71 | 
            +
             | 
| 85 72 | 
             
                    it 'posts the message with faraday' do
         | 
| 86 73 | 
             
                      connection = stub
         | 
| 87 74 | 
             
                      request = stub
         | 
| 88 75 | 
             
                      Faraday.stubs(:new).returns(connection)
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                      connection. | 
| 91 | 
            -
                      connection.stubs(:post).yields(request)
         | 
| 92 | 
            -
              
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                      connection.expects(:post).yields(request)
         | 
| 93 78 | 
             
                      request.stubs(:url)
         | 
| 94 79 | 
             
                      request.stubs(:body=)
         | 
| 95 80 | 
             
                      request.stubs(:headers).returns({})
         | 
| 81 | 
            +
                      connection.expects(:basic_auth).with('user1', 'password123abc')
         | 
| 96 82 |  | 
| 97 83 | 
             
                      MailRoom::Delivery::Postback.new(delivery_options).deliver('a message')
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                      expect(connection).to have_received(:basic_auth).with('user1', 'password123abc')
         | 
| 100 | 
            -
                      expect(connection).to have_received(:post)
         | 
| 101 | 
            -
                      
         | 
| 84 | 
            +
             | 
| 102 85 | 
             
                      expect(request.headers['Content-Type']).to eq('text/plain')
         | 
| 103 86 | 
             
                    end
         | 
| 104 87 | 
             
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  context 'with jwt token in the delivery options' do
         | 
| 90 | 
            +
                    let(:mailbox) {build_mailbox({
         | 
| 91 | 
            +
                      delivery_options: {
         | 
| 92 | 
            +
                        url: 'http://localhost/inbox',
         | 
| 93 | 
            +
                        jwt_auth_header: "Mailroom-Api-Request",
         | 
| 94 | 
            +
                        jwt_issuer: "mailroom",
         | 
| 95 | 
            +
                        jwt_algorithm: "HS256",
         | 
| 96 | 
            +
                        jwt_secret_path: "secret_path"
         | 
| 97 | 
            +
                      }
         | 
| 98 | 
            +
                    })}
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                    let(:delivery_options) {
         | 
| 101 | 
            +
                      MailRoom::Delivery::Postback::Options.new(mailbox)
         | 
| 102 | 
            +
                    }
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                    it 'posts the message with faraday' do
         | 
| 105 | 
            +
                      connection = stub
         | 
| 106 | 
            +
                      request = stub
         | 
| 107 | 
            +
                      Faraday.stubs(:new).returns(connection)
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                      connection.expects(:post).yields(request).twice
         | 
| 110 | 
            +
                      request.stubs(:url)
         | 
| 111 | 
            +
                      request.stubs(:body=)
         | 
| 112 | 
            +
                      request.stubs(:headers).returns({})
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                      jwt = stub
         | 
| 115 | 
            +
                      MailRoom::JWT.expects(:new).with(
         | 
| 116 | 
            +
                        header: 'Mailroom-Api-Request',
         | 
| 117 | 
            +
                        issuer: 'mailroom',
         | 
| 118 | 
            +
                        algorithm: 'HS256',
         | 
| 119 | 
            +
                        secret_path: 'secret_path'
         | 
| 120 | 
            +
                      ).returns(jwt)
         | 
| 121 | 
            +
                      jwt.stubs(:valid?).returns(true)
         | 
| 122 | 
            +
                      jwt.stubs(:header).returns('Mailroom-Api-Request')
         | 
| 123 | 
            +
                      jwt.stubs(:token).returns('a_jwt_token')
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                      delivery = MailRoom::Delivery::Postback.new(delivery_options)
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                      delivery.deliver('a message')
         | 
| 128 | 
            +
                      expect(request.headers['Mailroom-Api-Request']).to eql('a_jwt_token')
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                      # A different jwt token for the second time
         | 
| 131 | 
            +
                      jwt.stubs(:token).returns('another_jwt_token')
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                      delivery.deliver('another message')
         | 
| 134 | 
            +
                      expect(request.headers['Mailroom-Api-Request']).to eql('another_jwt_token')
         | 
| 135 | 
            +
                    end
         | 
| 136 | 
            +
                  end
         | 
| 105 137 | 
             
                end
         | 
| 106 138 | 
             
              end
         | 
| 107 139 | 
             
            end
         | 
| @@ -18,20 +18,15 @@ describe MailRoom::Delivery::Que do | |
| 18 18 | 
             
                let(:options) {MailRoom::Delivery::Que::Options.new(mailbox)}
         | 
| 19 19 |  | 
| 20 20 | 
             
                it 'stores the message in que_jobs table' do
         | 
| 21 | 
            -
                  PG. | 
| 22 | 
            -
                  connection.stubs(:exec)
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                  MailRoom::Delivery::Que.new(options).deliver('email')
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                  expect(PG).to have_received(:connect).with({
         | 
| 21 | 
            +
                  PG.expects(:connect).with({
         | 
| 27 22 | 
             
                    host: 'localhost',
         | 
| 28 23 | 
             
                    port: 5432,
         | 
| 29 24 | 
             
                    dbname: 'delivery_test',
         | 
| 30 25 | 
             
                    user: 'postgres',
         | 
| 31 26 | 
             
                    password: ''
         | 
| 32 | 
            -
                  })
         | 
| 27 | 
            +
                  }).returns(connection)
         | 
| 33 28 |  | 
| 34 | 
            -
                   | 
| 29 | 
            +
                  connection.expects(:exec).with(
         | 
| 35 30 | 
             
                    "INSERT INTO que_jobs (priority, job_class, queue, args) VALUES ($1, $2, $3, $4)",
         | 
| 36 31 | 
             
                    [
         | 
| 37 32 | 
             
                      5,
         | 
| @@ -40,6 +35,8 @@ describe MailRoom::Delivery::Que do | |
| 40 35 | 
             
                      JSON.dump(['email'])
         | 
| 41 36 | 
             
                    ]
         | 
| 42 37 | 
             
                  )
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  MailRoom::Delivery::Que.new(options).deliver('email')
         | 
| 43 40 | 
             
                end
         | 
| 44 41 | 
             
              end
         | 
| 45 42 | 
             
            end
         | 
| @@ -4,27 +4,49 @@ require 'mail_room/delivery/sidekiq' | |
| 4 4 | 
             
            describe MailRoom::Delivery::Sidekiq do
         | 
| 5 5 | 
             
              subject { described_class.new(options) }
         | 
| 6 6 | 
             
              let(:redis) { subject.send(:client) }
         | 
| 7 | 
            +
              let(:raw_client) { redis._client }
         | 
| 7 8 | 
             
              let(:options) { MailRoom::Delivery::Sidekiq::Options.new(mailbox) }
         | 
| 8 9 |  | 
| 9 10 | 
             
              describe '#options' do
         | 
| 10 11 | 
             
                let(:redis_url) { 'redis://localhost' }
         | 
| 12 | 
            +
                let(:redis_options) { { redis_url: redis_url } }
         | 
| 11 13 |  | 
| 12 14 | 
             
                context 'when only redis_url is specified' do
         | 
| 13 15 | 
             
                  let(:mailbox) {
         | 
| 14 16 | 
             
                    build_mailbox(
         | 
| 15 17 | 
             
                      delivery_method: :sidekiq,
         | 
| 16 | 
            -
                      delivery_options:  | 
| 17 | 
            -
                        redis_url: redis_url
         | 
| 18 | 
            -
                      }
         | 
| 18 | 
            +
                      delivery_options: redis_options
         | 
| 19 19 | 
             
                    )
         | 
| 20 20 | 
             
                  }
         | 
| 21 21 |  | 
| 22 | 
            -
                   | 
| 23 | 
            -
                     | 
| 22 | 
            +
                  context 'with simple redis url' do
         | 
| 23 | 
            +
                    it 'client has same specified redis_url' do
         | 
| 24 | 
            +
                      expect(raw_client.options[:url]).to eq(redis_url)
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    it 'client is a instance of RedisNamespace class' do
         | 
| 28 | 
            +
                      expect(redis).to be_a ::Redis
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    it 'connection has correct values' do
         | 
| 32 | 
            +
                      expect(redis.connection[:host]).to eq('localhost')
         | 
| 33 | 
            +
                      expect(redis.connection[:db]).to eq(0)
         | 
| 34 | 
            +
                    end
         | 
| 24 35 | 
             
                  end
         | 
| 25 36 |  | 
| 26 | 
            -
                   | 
| 27 | 
            -
                     | 
| 37 | 
            +
                  context 'with redis_db specified in options' do
         | 
| 38 | 
            +
                    before do
         | 
| 39 | 
            +
                      redis_options[:redis_db] = 4
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    it 'client has correct redis_url' do
         | 
| 43 | 
            +
                      expect(raw_client.options[:url]).to eq(redis_url)
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    it 'connection has correct values' do
         | 
| 47 | 
            +
                      expect(redis.connection[:host]).to eq('localhost')
         | 
| 48 | 
            +
                      expect(redis.connection[:db]).to eq(4)
         | 
| 49 | 
            +
                    end
         | 
| 28 50 | 
             
                  end
         | 
| 29 51 | 
             
                end
         | 
| 30 52 |  | 
| @@ -65,10 +87,10 @@ describe MailRoom::Delivery::Sidekiq do | |
| 65 87 | 
             
                  before { ::Redis::Client::Connector::Sentinel.any_instance.stubs(:resolve).returns(sentinels) }
         | 
| 66 88 |  | 
| 67 89 | 
             
                  it 'client has same specified sentinel params' do
         | 
| 68 | 
            -
                    expect( | 
| 69 | 
            -
                    expect( | 
| 70 | 
            -
                    expect( | 
| 71 | 
            -
                    expect( | 
| 90 | 
            +
                    expect(raw_client.instance_variable_get(:@connector)).to be_a Redis::Client::Connector::Sentinel
         | 
| 91 | 
            +
                    expect(raw_client.options[:host]).to eq('sentinel-master')
         | 
| 92 | 
            +
                    expect(raw_client.options[:password]).to eq('mypassword')
         | 
| 93 | 
            +
                    expect(raw_client.options[:sentinels]).to eq(sentinels)
         | 
| 72 94 | 
             
                  end
         | 
| 73 95 | 
             
                end
         | 
| 74 96 |  | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe MailRoom::HealthCheck do
         | 
| 6 | 
            +
              let(:address) { '127.0.0.1' }
         | 
| 7 | 
            +
              let(:port) { 8000 }
         | 
| 8 | 
            +
              let(:params) { { address: address, port: port } }
         | 
| 9 | 
            +
              subject { described_class.new(params) }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              describe '#initialize' do
         | 
| 12 | 
            +
                context 'with valid parameters' do
         | 
| 13 | 
            +
                  it 'validates successfully' do
         | 
| 14 | 
            +
                    expect(subject).to be_a(described_class)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                context 'with invalid address' do
         | 
| 19 | 
            +
                  let(:address) { nil }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  it 'raises an error' do
         | 
| 22 | 
            +
                    expect { subject }.to raise_error('No health check address specified')
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                context 'with invalid port' do
         | 
| 27 | 
            +
                  let(:port) { nil }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  it 'raises an error' do
         | 
| 30 | 
            +
                    expect { subject }.to raise_error('Health check port 0 is invalid')
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              describe '#run' do
         | 
| 36 | 
            +
                it 'sets running to true' do
         | 
| 37 | 
            +
                  server = stub(start: true)
         | 
| 38 | 
            +
                  subject.stubs(:create_server).returns(server)
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  subject.run
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  expect(subject.running).to be true
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              describe '#quit' do
         | 
| 47 | 
            +
                it 'sets running to false' do
         | 
| 48 | 
            +
                  server = stub(start: true, shutdown: true)
         | 
| 49 | 
            +
                  subject.stubs(:create_server).returns(server)
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  subject.run
         | 
| 52 | 
            +
                  subject.quit
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  expect(subject.running).to be false
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 |  | 
| 3 | 
            -
            describe MailRoom::Connection do
         | 
| 3 | 
            +
            describe MailRoom::IMAP::Connection do
         | 
| 4 4 | 
             
              let(:imap) {stub}
         | 
| 5 5 | 
             
              let(:mailbox) {build_mailbox(delete_after_delivery: true, expunge_deleted: true)}
         | 
| 6 6 |  | 
| @@ -9,7 +9,9 @@ describe MailRoom::Connection do | |
| 9 9 | 
             
              end
         | 
| 10 10 |  | 
| 11 11 | 
             
              context "with imap set up" do
         | 
| 12 | 
            -
                let(:connection) {MailRoom::Connection.new(mailbox)}
         | 
| 12 | 
            +
                let(:connection) {MailRoom::IMAP::Connection.new(mailbox)}
         | 
| 13 | 
            +
                let(:uid) { 1 }
         | 
| 14 | 
            +
                let(:seqno) { 8 }
         | 
| 13 15 |  | 
| 14 16 | 
             
                before :each do
         | 
| 15 17 | 
             
                  imap.stubs(:starttls)
         | 
| @@ -36,30 +38,24 @@ describe MailRoom::Connection do | |
| 36 38 | 
             
                end
         | 
| 37 39 |  | 
| 38 40 | 
             
                it "waits for a message to process" do
         | 
| 39 | 
            -
                  new_message = 'a message'
         | 
| 40 | 
            -
                  new_message.stubs(:seqno).returns(8)
         | 
| 41 | 
            +
                  new_message = MailRoom::IMAP::Message.new(uid: uid, body: 'a message', seqno: seqno)
         | 
| 41 42 |  | 
| 42 43 | 
             
                  connection.on_new_message do |message|
         | 
| 43 44 | 
             
                    expect(message).to eq(new_message)
         | 
| 44 45 | 
             
                    true
         | 
| 45 46 | 
             
                  end
         | 
| 46 47 |  | 
| 47 | 
            -
                   | 
| 48 | 
            +
                  attr = { 'UID' => uid, 'RFC822' => new_message.body }
         | 
| 49 | 
            +
                  fetch_data = Net::IMAP::FetchData.new(seqno, attr)
         | 
| 48 50 |  | 
| 49 | 
            -
                  imap. | 
| 50 | 
            -
                  imap.stubs(:uid_search). | 
| 51 | 
            -
                  imap. | 
| 52 | 
            -
                   | 
| 53 | 
            -
                  imap. | 
| 51 | 
            +
                  imap.expects(:idle)
         | 
| 52 | 
            +
                  imap.stubs(:uid_search).with(mailbox.search_command).returns([], [uid])
         | 
| 53 | 
            +
                  imap.expects(:uid_fetch).with([uid], "RFC822").returns([fetch_data])
         | 
| 54 | 
            +
                  mailbox.expects(:deliver?).with(uid).returns(true)
         | 
| 55 | 
            +
                  imap.expects(:store).with(seqno, "+FLAGS", [Net::IMAP::DELETED])
         | 
| 56 | 
            +
                  imap.expects(:expunge).once
         | 
| 54 57 |  | 
| 55 58 | 
             
                  connection.wait
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                  expect(imap).to have_received(:idle)
         | 
| 58 | 
            -
                  expect(imap).to have_received(:uid_search).with(mailbox.search_command).twice
         | 
| 59 | 
            -
                  expect(imap).to have_received(:uid_fetch).with([1], "RFC822")
         | 
| 60 | 
            -
                  expect(mailbox).to have_received(:deliver?).with(1)
         | 
| 61 | 
            -
                  expect(imap).to have_received(:store).with(8, "+FLAGS", [Net::IMAP::DELETED])
         | 
| 62 | 
            -
                  expect(imap).to have_received(:expunge).once
         | 
| 63 59 | 
             
                end
         | 
| 64 60 | 
             
              end
         | 
| 65 61 | 
             
            end
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            # frozen_string_literal:true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
            require 'securerandom'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            describe MailRoom::IMAP::Message do
         | 
| 7 | 
            +
              let(:uid) { SecureRandom.hex }
         | 
| 8 | 
            +
              let(:body) { 'hello world' }
         | 
| 9 | 
            +
              let(:seqno) { 5 }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              subject { described_class.new(uid: uid, body: body, seqno: seqno) }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              describe '#initalize' do
         | 
| 14 | 
            +
                it 'initializes with required parameters' do
         | 
| 15 | 
            +
                  subject
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  expect(subject.uid).to eq(uid)
         | 
| 18 | 
            +
                  expect(subject.body).to eq(body)
         | 
| 19 | 
            +
                  expect(subject.seqno).to eq(seqno)
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              describe '#==' do
         | 
| 24 | 
            +
                let(:dup) { described_class.new(uid: uid, body: body, seqno: seqno) }
         | 
| 25 | 
            +
                let(:base_msg) { MailRoom::Message.new(uid: uid, body: body) }
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                it 'matches an equivalent message' do
         | 
| 28 | 
            +
                  expect(dup == subject).to be true
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                it 'does not match a base message' do
         | 
| 32 | 
            +
                  expect(subject == base_msg).to be false
         | 
| 33 | 
            +
                  expect(base_msg == subject).to be false
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
            end
         | 
| @@ -0,0 +1,80 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'mail_room/jwt'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe MailRoom::JWT do
         | 
| 6 | 
            +
              let(:secret_path) { File.expand_path('../fixtures/jwt_secret', File.dirname(__FILE__)) }
         | 
| 7 | 
            +
              let(:secret) { Base64.strict_decode64(File.read(secret_path).chomp) }
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              let(:standard_config) do
         | 
| 10 | 
            +
                {
         | 
| 11 | 
            +
                  secret_path: secret_path,
         | 
| 12 | 
            +
                  issuer: 'mailroom',
         | 
| 13 | 
            +
                  header: 'Mailroom-Api-Request',
         | 
| 14 | 
            +
                  algorithm: 'HS256'
         | 
| 15 | 
            +
                }
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              describe '#token' do
         | 
| 19 | 
            +
                let(:jwt) { described_class.new(**standard_config) }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                it 'generates a valid jwt token' do
         | 
| 22 | 
            +
                  token = jwt.token
         | 
| 23 | 
            +
                  expect(token).not_to be_empty
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  payload = nil
         | 
| 26 | 
            +
                  expect do
         | 
| 27 | 
            +
                    payload = JWT.decode(token, secret, true, iss: 'mailroom', verify_iat: true, verify_iss: true, algorithm: 'HS256')
         | 
| 28 | 
            +
                  end.not_to raise_error
         | 
| 29 | 
            +
                  expect(payload).to be_an(Array)
         | 
| 30 | 
            +
                  expect(payload).to match(
         | 
| 31 | 
            +
                    [
         | 
| 32 | 
            +
                      a_hash_including(
         | 
| 33 | 
            +
                        'iss' => 'mailroom',
         | 
| 34 | 
            +
                        'nonce' => be_a(String),
         | 
| 35 | 
            +
                        'iat' => be_a(Integer)
         | 
| 36 | 
            +
                      ),
         | 
| 37 | 
            +
                      { 'alg' => 'HS256' }
         | 
| 38 | 
            +
                    ]
         | 
| 39 | 
            +
                  )
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                it 'generates a different token for each invocation' do
         | 
| 43 | 
            +
                  expect(jwt.token).not_to eql(jwt.token)
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              describe '#valid?' do
         | 
| 48 | 
            +
                it 'returns true if all essential components are present' do
         | 
| 49 | 
            +
                  jwt = described_class.new(**standard_config)
         | 
| 50 | 
            +
                  expect(jwt.valid?).to eql(true)
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                it 'returns true if header and secret path are present' do
         | 
| 54 | 
            +
                  jwt = described_class.new(
         | 
| 55 | 
            +
                    secret_path: secret_path,
         | 
| 56 | 
            +
                    header: 'Mailroom-Api-Request',
         | 
| 57 | 
            +
                    issuer: nil,
         | 
| 58 | 
            +
                    algorithm: nil
         | 
| 59 | 
            +
                  )
         | 
| 60 | 
            +
                  expect(jwt.valid?).to eql(true)
         | 
| 61 | 
            +
                  expect(jwt.issuer).to eql(described_class::DEFAULT_ISSUER)
         | 
| 62 | 
            +
                  expect(jwt.algorithm).to eql(described_class::DEFAULT_ALGORITHM)
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                it 'returns false if either header or secret_path are missing' do
         | 
| 66 | 
            +
                  expect(described_class.new(
         | 
| 67 | 
            +
                    secret_path: nil,
         | 
| 68 | 
            +
                    header: 'Mailroom-Api-Request',
         | 
| 69 | 
            +
                    issuer: nil,
         | 
| 70 | 
            +
                    algorithm: nil
         | 
| 71 | 
            +
                  ).valid?).to eql(false)
         | 
| 72 | 
            +
                  expect(described_class.new(
         | 
| 73 | 
            +
                    secret_path: secret_path,
         | 
| 74 | 
            +
                    header: nil,
         | 
| 75 | 
            +
                    issuer: nil,
         | 
| 76 | 
            +
                    algorithm: nil
         | 
| 77 | 
            +
                  ).valid?).to eql(false)
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
            end
         | 
| @@ -5,6 +5,7 @@ describe MailRoom::Logger::Structured do | |
| 5 5 | 
             
              subject { described_class.new $stdout }
         | 
| 6 6 |  | 
| 7 7 | 
             
              let!(:now) { Time.now }
         | 
| 8 | 
            +
              let(:timestamp) { now.to_datetime.iso8601(3) }
         | 
| 8 9 | 
             
              let(:message) { { action: 'exciting development', message: 'testing 123' } }
         | 
| 9 10 |  | 
| 10 11 | 
             
              before do
         | 
| @@ -32,7 +33,7 @@ describe MailRoom::Logger::Structured do | |
| 32 33 | 
             
                  }
         | 
| 33 34 | 
             
                  expected = {
         | 
| 34 35 | 
             
                      severity: 'DEBUG',
         | 
| 35 | 
            -
                      time:  | 
| 36 | 
            +
                      time: timestamp,
         | 
| 36 37 | 
             
                      additional_field: "some value"
         | 
| 37 38 | 
             
                  }
         | 
| 38 39 |  | 
| @@ -40,10 +41,41 @@ describe MailRoom::Logger::Structured do | |
| 40 41 | 
             
                end
         | 
| 41 42 | 
             
              end
         | 
| 42 43 |  | 
| 44 | 
            +
              describe '#format_message' do
         | 
| 45 | 
            +
                shared_examples 'timestamp formatting' do
         | 
| 46 | 
            +
                  it 'outputs ISO8601 timestamps' do
         | 
| 47 | 
            +
                    data = JSON.parse(subject.format_message('debug', input_timestamp, 'test', { message: 'hello' } ))
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    expect(data['time']).to eq(expected_timestamp)
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                context 'with no timestamp' do
         | 
| 54 | 
            +
                  let(:input_timestamp) { nil }
         | 
| 55 | 
            +
                  let(:expected_timestamp) { timestamp }
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  it_behaves_like 'timestamp formatting'
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                context 'with DateTime' do
         | 
| 61 | 
            +
                  let(:input_timestamp) { now.to_datetime }
         | 
| 62 | 
            +
                  let(:expected_timestamp) { timestamp }
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  it_behaves_like 'timestamp formatting'
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                context 'with string' do
         | 
| 68 | 
            +
                  let(:input_timestamp) { now.to_s }
         | 
| 69 | 
            +
                  let(:expected_timestamp) { input_timestamp }
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  it_behaves_like 'timestamp formatting'
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 43 75 | 
             
              def json_matching(level, message)
         | 
| 44 76 | 
             
                contents = {
         | 
| 45 77 | 
             
                    severity: level,
         | 
| 46 | 
            -
                    time:  | 
| 78 | 
            +
                    time: timestamp
         | 
| 47 79 | 
             
                }.merge(message)
         | 
| 48 80 |  | 
| 49 81 | 
             
                as_regex(contents)
         |