File: explicit_encryption_context_spec.rb

package info (click to toggle)
ruby-mongo 2.23.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 15,020 kB
  • sloc: ruby: 110,810; makefile: 5
file content (266 lines) | stat: -rw-r--r-- 7,871 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# frozen_string_literal: true
# rubocop:todo all

require 'mongo'
require 'lite_spec_helper'

describe Mongo::Crypt::ExplicitEncryptionContext do
  require_libmongocrypt
  include_context 'define shared FLE helpers'

  let(:credentials) { Mongo::Crypt::KMS::Credentials.new(kms_providers) }
  let(:mongocrypt) { Mongo::Crypt::Handle.new(credentials, logger: logger) }
  let(:context) { described_class.new(mongocrypt, io, value, options) }

  let(:logger) { nil }

  let(:io) { double("Mongo::ClientEncryption::IO") }
  let(:value) { { 'v': 'Hello, world!' } }

  let(:options) do
    {
      key_id: key_id,
      key_alt_name: key_alt_name,
      algorithm: algorithm
    }
  end

  describe '#initialize' do
    shared_examples 'a functioning ExplicitEncryptionContext' do
      context 'with nil key_id and key_alt_name options' do
        let(:key_id) { nil }
        let(:key_alt_name) { nil }

        it 'raises an exception' do
          expect do
            context
          end.to raise_error(ArgumentError, /:key_id and :key_alt_name options cannot both be nil/)
        end
      end

      context 'with both key_id and key_alt_name options' do
        it 'raises an exception' do
          expect do
            context
          end.to raise_error(ArgumentError, /:key_id and :key_alt_name options cannot both be present/)
        end
      end

      context 'with invalid key_id' do
        let(:key_id) { 'random string' }
        let(:key_alt_name) { nil }

        it 'raises an exception' do
          expect do
            context
          end.to raise_error(ArgumentError, /Expected the :key_id option to be a BSON::Binary object/)
        end
      end

      context 'with invalid key_alt_name' do
        let(:key_id) { nil }
        let(:key_alt_name) { 5 }

        it 'raises an exception' do
          expect do
            context
          end.to raise_error(ArgumentError, /key_alt_name option must be a String/)
        end
      end

      context 'with valid key_alt_name' do
        let(:key_id) { nil }

        context 'with nil algorithm' do
          let(:algorithm) { nil }

          it 'raises exception' do
            expect do
              context
            end.to raise_error(Mongo::Error::CryptError, /passed null algorithm/)
          end
        end

        context 'with invalid algorithm' do
          let(:algorithm) { 'unsupported-algorithm' }

          it 'raises an exception' do
            expect do
              context
            end.to raise_error(Mongo::Error::CryptError, /unsupported algorithm/)
          end
        end

        it 'initializes context' do
          expect do
            context
          end.not_to raise_error
        end
      end

      context 'with valid key_id' do
        let(:key_alt_name) { nil }

        context 'with nil algorithm' do
          let(:algorithm) { nil }

          it 'raises exception' do
            expect do
              context
            end.to raise_error(Mongo::Error::CryptError, /passed null algorithm/)
          end
        end

        context 'with invalid algorithm' do
          let(:algorithm) { 'unsupported-algorithm' }

          it 'raises an exception' do
            expect do
              context
            end.to raise_error(Mongo::Error::CryptError, /unsupported algorithm/)
          end
        end

        it 'initializes context' do
          expect do
            context
          end.not_to raise_error
        end
      end

      context 'with query_type' do
        let(:key_alt_name) { nil }

        it 'raises exception' do
          expect do
            described_class.new(
              mongocrypt,
              io,
              value,
              options.merge(query_type: "equality")
            )
          end.to raise_error(ArgumentError, /query_type is allowed only for "Indexed" or "Range" algorithm/)
        end
      end

      context 'with contention_factor' do
        let(:key_alt_name) { nil }

        it 'raises exception' do
          expect do
            described_class.new(
              mongocrypt,
              io,
              value,
              options.merge(contention_factor: 10)
            )
          end.to raise_error(ArgumentError, /contention_factor is allowed only for "Indexed" or "Range" algorithm/)
        end
      end

      context 'with Indexed algorithm' do
        let(:algorithm) do
          'Indexed'
        end

        let(:key_alt_name) do
          nil
        end

        it 'initializes context' do
          expect do
            described_class.new(
              mongocrypt,
              io,
              value,
              options.merge(contention_factor: 0)
            )
          end.not_to raise_error
        end

        context 'with query_type' do
          it 'initializes context' do
            expect do
              described_class.new(
                mongocrypt,
                io,
                value,
                options.merge(query_type: "equality", contention_factor: 0)
              )
            end.not_to raise_error
          end
        end

        context 'with contention_factor' do
          it 'initializes context' do
            expect do
              described_class.new(
                mongocrypt,
                io,
                value,
                options.merge(contention_factor: 10)
              )
            end.not_to raise_error
          end
        end
      end
    end

    context 'when mongocrypt is initialized with AWS KMS provider options' do
      include_context 'with AWS kms_providers'
      it_behaves_like 'a functioning ExplicitEncryptionContext'
    end

    context 'when mongocrypt is initialized with Azure KMS provider options' do
      include_context 'with Azure kms_providers'
      it_behaves_like 'a functioning ExplicitEncryptionContext'
    end

    context 'when mongocrypt is initialized with GCP KMS provider options' do
      include_context 'with GCP kms_providers'
      it_behaves_like 'a functioning ExplicitEncryptionContext'
    end

    context 'when mongocrypt is initialized with KMIP KMS provider options' do
      include_context 'with KMIP kms_providers'
      it_behaves_like 'a functioning ExplicitEncryptionContext'
    end

    context 'when mongocrypt is initialized with local KMS provider options' do
      include_context 'with local kms_providers'
      it_behaves_like 'a functioning ExplicitEncryptionContext'
    end

    context 'with verbose logging' do
      include_context 'with local kms_providers'

      before(:all) do
        # Logging from libmongocrypt requires the C library to be built with the -DENABLE_TRACE=ON
        # option; none of the pre-built packages on Evergreen have been built with logging enabled.
        #
        # It is still useful to be able to run these tests locally to confirm that logging is working
        # while debugging any problems.
        #
        # For now, skip this test by default and revisit once we have determined how we want to
        # package libmongocrypt with the Ruby driver (see: https://jira.mongodb.org/browse/RUBY-1966)
        skip "These tests require libmongocrypt to be built with the '-DENABLE_TRACE=ON' cmake option." +
          " They also require the MONGOCRYPT_TRACE environment variable to be set to 'ON'."
      end

      let(:key_alt_name) { nil }
      let(:logger) do
        ::Logger.new(STDOUT).tap do |logger|
          logger.level = ::Logger::DEBUG
        end
      end

      it 'receives log messages from libmongocrypt' do
        expect(logger).to receive(:debug).with(/mongocrypt_ctx_setopt_key_id/)
        expect(logger).to receive(:debug).with(/mongocrypt_ctx_setopt_algorithm/)
        expect(logger).to receive(:debug).with(/mongocrypt_ctx_explicit_encrypt_init/)

        context
      end
    end
  end
end