Skip to content

Commit 9154678

Browse files
authored
Merge pull request #47 from cipherstash/chore/update-go-xorm-tests
Update go xorm tests
2 parents a5e9dad + 70ed523 commit 9154678

File tree

12 files changed

+289
-538
lines changed

12 files changed

+289
-538
lines changed

languages/go/goeql

Submodule goeql deleted from 3765997

languages/go/xorm/README.md

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,6 @@ Start Postgres and CipherStash Proxy and install EQL:
6868
./run.sh setup
6969
```
7070

71-
Run examples:
72-
73-
```shell
74-
./run.sh examples
75-
```
76-
7771
Run tests:
7872

7973
```shell
@@ -190,7 +184,7 @@ Example:
190184
SELECT cs_add_index_v1('examples', 'encrypted_text_field', 'unique', 'text', '{"token_filters": [{"kind": "downcase"}]}');
191185
SELECT cs_add_index_v1('examples', 'encrypted_text_field', 'match', 'text');
192186
SELECT cs_add_index_v1('examples', 'encrypted_text_field', 'ore', 'text');
193-
SELECT cs_add_index_v1('examples', 'encrypted_jsonb_field', 'ste_vec', 'jsonb', '{"prefix": "some-prefix"}');
187+
SELECT cs_add_index_v1('examples', 'encrypted_jsonb_field', 'ste_vec', 'jsonb', '{"prefix": "examples/encrypted_jsonb_field"}');
194188

195189
-- The below indexes will also need to be added to enable full search functionality on the encrypted columns
196190

@@ -229,7 +223,7 @@ Goeql has functions that will serialize a value into the format required by Ciph
229223

230224
[These functions](https://github.com/cipherstash/encrypt-query-language/blob/main/languages/go/goeql/goeql.go#L153-L171) will need to be used for the relevant query.
231225

232-
Examples of how to use these are in the [example_queries.go](./example_queries.go) file.
226+
Examples of how to use these are in the [e2e_test.go](./e2e_test.go) file.
233227

234228
Below is an example of running a match query on a text field.
235229

languages/go/xorm/docker-compose.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
services:
22
postgres:
33
container_name: gotest_pg
4+
build:
5+
context: ./init-db
46
image: postgres:16.2-bookworm
57
environment:
68
POSTGRES_USER: postgres
@@ -13,7 +15,7 @@ services:
1315
- ./init-db:/docker-entrypoint-initdb.d
1416
proxy:
1517
container_name: gotest_proxy
16-
image: cipherstash/cipherstash-proxy:cipherstash-proxy-v0.1.0
18+
image: cipherstash/cipherstash-proxy:cipherstash-proxy-v0.3.1
1719
depends_on:
1820
- postgres
1921
ports:
@@ -23,6 +25,7 @@ services:
2325
CS_CLIENT_ACCESS_KEY: $CS_CLIENT_ACCESS_KEY
2426
CS_ENCRYPTION__CLIENT_ID: $CS_ENCRYPTION__CLIENT_ID
2527
CS_ENCRYPTION__CLIENT_KEY: $CS_ENCRYPTION__CLIENT_KEY
28+
CS_ENCRYPTION__DATASET_ID: $CS_ENCRYPTION__DATASET_ID
2629
CS_TEST_ON_CHECKOUT: "true"
2730
CS_AUDIT__ENABLED: "false"
2831
CS_DATABASE__PORT: 5432

languages/go/xorm/e2e_test.go

Lines changed: 259 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package main
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"log"
7+
"reflect"
68
"testing"
79

810
"github.com/cipherstash/goeql"
@@ -181,7 +183,7 @@ func TestMatchQueryEmail(t *testing.T) {
181183
assert.Equal(t, EncryptedTextField("testemail@test.com"), returnedExample.EncryptedTextField, "EncryptedTextField should match")
182184
}
183185

184-
func TestJsonbQuerySimple(t *testing.T) {
186+
func TestJsonbQueryContainment(t *testing.T) {
185187
engine := proxyEngine()
186188
truncateDb(engine)
187189

@@ -242,7 +244,7 @@ func TestJsonbQuerySimple(t *testing.T) {
242244
assert.Equal(t, EncryptedJsonbField(expectedJson), returnedExample.EncryptedJsonbField, "EncryptedJsonb field should match")
243245
}
244246

245-
func TestJsonbQueryNested(t *testing.T) {
247+
func TestJsonbQueryNestedContainment(t *testing.T) {
246248
engine := proxyEngine()
247249
truncateDb(engine)
248250

@@ -308,6 +310,250 @@ func TestJsonbQueryNested(t *testing.T) {
308310
assert.Equal(t, EncryptedJsonbField(expectedJson), returnedExample.EncryptedJsonbField, "EncryptedJsonb field should match")
309311
}
310312

313+
func TestJsonbExtractionOp(t *testing.T) {
314+
engine := proxyEngine()
315+
truncateDb(engine)
316+
317+
expected_one := map[string]interface{}{
318+
"nested_two": "hello world",
319+
}
320+
jsonOne := map[string]interface{}{
321+
"top": map[string]interface{}{
322+
"integer": float64(101),
323+
"float": 1.234,
324+
"string": "some string",
325+
"nested": expected_one,
326+
},
327+
"bottom": "value_three",
328+
}
329+
expected_two := map[string]interface{}{
330+
"nested_two": "foo bar",
331+
}
332+
jsonTwo := map[string]interface{}{
333+
"top": map[string]interface{}{
334+
"integer": float64(101),
335+
"float": 1.234,
336+
"string": "some string",
337+
"nested": expected_two,
338+
},
339+
"bottom": "value_three",
340+
}
341+
342+
examples := []Example{
343+
{
344+
NonEncryptedField: "sydney",
345+
EncryptedTextField: "testing",
346+
EncryptedIntField: 42,
347+
EncryptedJsonbField: jsonOne,
348+
},
349+
{
350+
NonEncryptedField: "melbourne",
351+
EncryptedIntField: 42,
352+
EncryptedTextField: "someone@gmail.com",
353+
EncryptedJsonbField: jsonTwo,
354+
},
355+
}
356+
357+
inserted, err := engine.Insert(&examples)
358+
359+
if err != nil {
360+
t.Errorf("Error inserting examples: %v", err)
361+
}
362+
363+
assert.Equal(t, int64(2), inserted, "Expected to insert 2 rows")
364+
365+
sql := `SELECT cs_ste_vec_value_v1(encrypted_jsonb_field, ?) AS val FROM examples`
366+
ejson_path, err := goeql.EJsonPathQuery("$.top.nested", "examples", "encrypted_jsonb_field")
367+
368+
if err != nil {
369+
log.Fatalf("Error serializing fields_encrypted query: %v", err)
370+
}
371+
results, err := engine.Query(sql, ejson_path)
372+
if err != nil {
373+
t.Fatalf("Could not retrieve example using extraction: %v", err)
374+
}
375+
376+
assert.Equal(t, 2, len(results))
377+
378+
for i := range results {
379+
380+
var encryptedJson goeql.EncryptedJsonb
381+
382+
deserializedValue, err := encryptedJson.Deserialize(results[i]["val"])
383+
if err != nil {
384+
log.Fatal("Deserialization error:", err)
385+
}
386+
jsonb_expected_one := goeql.EncryptedJsonb(expected_one)
387+
jsonb_expected_two := goeql.EncryptedJsonb(expected_two)
388+
389+
if !reflect.DeepEqual(deserializedValue, jsonb_expected_one) && !reflect.DeepEqual(deserializedValue, jsonb_expected_two) {
390+
t.Errorf("Expected value to be either %v or %v, but got %v", jsonb_expected_one, jsonb_expected_two, deserializedValue)
391+
}
392+
393+
}
394+
}
395+
396+
func TestJsonbComparisonOp(t *testing.T) {
397+
engine := proxyEngine()
398+
truncateDb(engine)
399+
400+
jsonOne := map[string]interface{}{
401+
"top": map[string]interface{}{
402+
"integer": 3,
403+
"float": 1.234,
404+
"string": "some string",
405+
},
406+
"bottom": "value_three",
407+
}
408+
jsonTwo := map[string]interface{}{
409+
"top": map[string]interface{}{
410+
"integer": 50,
411+
"float": 1.234,
412+
"string": "some string",
413+
},
414+
"bottom": "value_three",
415+
}
416+
expected_id := int64(2)
417+
example_one := Example{
418+
Id: int64(1),
419+
NonEncryptedField: "sydney",
420+
EncryptedTextField: "testing",
421+
EncryptedIntField: 42,
422+
EncryptedJsonbField: jsonOne,
423+
}
424+
example_two := Example{
425+
Id: expected_id,
426+
NonEncryptedField: "melbourne",
427+
EncryptedIntField: 42,
428+
EncryptedTextField: "someone@gmail.com",
429+
EncryptedJsonbField: jsonTwo,
430+
}
431+
432+
examples := []Example{
433+
example_one,
434+
example_two,
435+
}
436+
437+
inserted, err := engine.Insert(&examples)
438+
439+
if err != nil {
440+
t.Errorf("Error inserting examples: %v", err)
441+
}
442+
443+
assert.Equal(t, int64(2), inserted, "Expected to insert 2 rows")
444+
445+
path := "$.top.integer"
446+
ejson_path, err := goeql.EJsonPathQuery(path, "examples", "encrypted_jsonb_field")
447+
448+
if err != nil {
449+
log.Fatalf("Error serializing fields_encrypted query: %v", err)
450+
}
451+
value := 10
452+
comparison_value, err := goeql.JsonbQuery(value, "examples", "encrypted_jsonb_field")
453+
454+
if err != nil {
455+
log.Fatalf("Error marshaling comparison value: %v", err)
456+
}
457+
var results []Example
458+
err = engine.Where("cs_ste_vec_term_v1(examples.encrypted_jsonb_field, ?) > cs_ste_vec_term_v1(?)", ejson_path, comparison_value).Find(&results)
459+
460+
if err != nil {
461+
t.Fatalf("Could not retrieve example using comparison op: %v", err)
462+
}
463+
464+
assert.Equal(t, 1, len(results))
465+
assert.Equal(t, expected_id, results[0].Id)
466+
}
467+
468+
func TestJsonbTermsOp(t *testing.T) {
469+
engine := proxyEngine()
470+
truncateDb(engine)
471+
472+
jsonOne := map[string]interface{}{
473+
"top": map[string]interface{}{
474+
"integer": 3,
475+
"float": 1.234,
476+
"string": "some string",
477+
"nums": []int64{1, 2, 3},
478+
},
479+
"bottom": "value_three",
480+
}
481+
jsonTwo := map[string]interface{}{
482+
"top": map[string]interface{}{
483+
"integer": 50,
484+
"float": 1.234,
485+
"string": "some string",
486+
"nums": []int64{4, 5, 6},
487+
},
488+
"bottom": "value_three",
489+
}
490+
expected_id := int64(2)
491+
example_one := Example{
492+
Id: int64(1),
493+
NonEncryptedField: "sydney",
494+
EncryptedTextField: "testing",
495+
EncryptedIntField: 42,
496+
EncryptedJsonbField: jsonOne,
497+
EncryptedBoolField: true,
498+
}
499+
example_two := Example{
500+
Id: expected_id,
501+
NonEncryptedField: "melbourne",
502+
EncryptedIntField: 42,
503+
EncryptedTextField: "someone@gmail.com",
504+
EncryptedJsonbField: jsonTwo,
505+
EncryptedBoolField: false,
506+
}
507+
508+
examples := []Example{
509+
example_one,
510+
example_two,
511+
}
512+
513+
inserted, err := engine.Insert(&examples)
514+
515+
if err != nil {
516+
t.Errorf("Error inserting examples: %v", err)
517+
}
518+
519+
assert.Equal(t, int64(2), inserted, "Expected to insert 2 rows")
520+
521+
// Serialize value as jsonb
522+
value := 5
523+
comparison_value, err := goeql.JsonbQuery(value, "examples", "encrypted_jsonb_field")
524+
if err != nil {
525+
log.Fatalf("Error marshaling comparison value: %v", err)
526+
}
527+
// Serialize path
528+
path := "$.top.nums[*]"
529+
ejson_path, err := goeql.EJsonPathQuery(path, "examples", "encrypted_jsonb_field")
530+
531+
sql := `SELECT * from examples e
532+
WHERE EXISTS (
533+
SELECT 1
534+
FROM unnest(cs_ste_vec_terms_v1(e.encrypted_jsonb_field, ?)) AS term
535+
WHERE term > cs_ste_vec_term_v1(?)
536+
)`
537+
538+
if err != nil {
539+
log.Fatalf("Error serializing encrypted_jsonb_field query: %v", err)
540+
}
541+
542+
results, err := engine.Query(sql, ejson_path, comparison_value)
543+
if err != nil {
544+
t.Fatalf("Could not retrieve example using terms: %v", err)
545+
}
546+
547+
assert.Equal(t, 1, len(results))
548+
549+
var jsonData int64
550+
if err := json.Unmarshal(results[0]["id"], &jsonData); err != nil {
551+
t.Fatalf("Could not unmarshal %v", err)
552+
}
553+
assert.Equal(t, expected_id, jsonData)
554+
555+
}
556+
311557
func TestOreStringRangeQuery(t *testing.T) {
312558
engine := proxyEngine()
313559
truncateDb(engine)
@@ -513,3 +759,14 @@ func TestUniqueStringQuery(t *testing.T) {
513759

514760
assert.Equal(t, expected, returnedExample.EncryptedTextField, "EncryptedText field should match")
515761
}
762+
763+
func generateJsonbData(value_one string, value_two string, value_three string) map[string]any {
764+
data := map[string]any{
765+
"top": map[string]any{
766+
"nested": []any{value_one, value_two},
767+
},
768+
"bottom": value_three,
769+
}
770+
771+
return data
772+
}

0 commit comments

Comments
 (0)