github.com/weaviate/weaviate@v1.24.6/test/acceptance/schema/transactions_test.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package test 13 14 import ( 15 "bytes" 16 "fmt" 17 "io" 18 "net/http" 19 "testing" 20 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/require" 23 ) 24 25 // This test makes sure that a malformed tx payload (possibly from a bad actor) 26 // can't crash - or possibly worse - deadlock Weaviate 27 // 28 // See https://github.com/weaviate/weaviate/issues/3401 for details 29 func TestCrashServerThroughInvalidTxPayloads(t *testing.T) { 30 tests := []struct { 31 name string 32 txId string 33 payload string 34 errMustContain string 35 }{ 36 { 37 name: "add_class: empty class payload", 38 txId: "1", 39 payload: `{"id":"1", "type": "add_class", "payload":{}}`, 40 errMustContain: "class is nil", 41 }, 42 { 43 name: "add_class: class set, but empty, no state", 44 txId: "2", 45 payload: `{"id":"2", "type": "add_class", "payload":{"class":{}}}`, 46 errMustContain: "state is nil", 47 }, 48 { 49 name: "add_class: class set and valid, no state", 50 txId: "3", 51 payload: `{"id":"3", "type": "add_class", "payload":{"class":{"vectorIndexType":"hnsw","class":"Foo"}}}`, 52 errMustContain: "state is nil", 53 }, 54 { 55 name: "add_class: class set, but empty, with state", 56 txId: "4", 57 payload: `{"id":"4", "type": "add_class", "payload":{"state":{},"class":{}}}`, 58 errMustContain: "unsupported vector index", 59 }, 60 { 61 name: "update_class: empty class payload", 62 txId: "1", 63 payload: `{"id":"1", "type": "update_class", "payload":{}}`, 64 errMustContain: "class is nil", 65 }, 66 { 67 name: "update_class: class set and valid, no state", 68 txId: "3", 69 payload: `{"id":"3", "type": "update_class", "payload":{"class":{"vectorIndexType":"hnsw","class":"FoobarBazzzar"}}}`, 70 }, 71 { 72 name: "update_class: class set, but empty, with state", 73 txId: "4", 74 payload: `{"id":"4", "type": "update_class", "payload":{"state":{},"class":{}}}`, 75 errMustContain: "unsupported vector index", 76 }, 77 { 78 name: "add_tenants: empty payload", 79 txId: "1", 80 payload: `{"id":"1", "type": "add_tenants", "payload":{}}`, 81 errMustContain: "not found", 82 }, 83 { 84 name: "delete_tenants: malformed payload", 85 txId: "1", 86 payload: `{"id":"1", "type": "delete_tenants", "payload":7}`, 87 errMustContain: "invalid", 88 }, 89 { 90 name: "delete_class: malformed payload", 91 txId: "2", 92 payload: `{"id":"2", "type": "delete_class", "payload":7}`, 93 errMustContain: "invalid", 94 }, 95 { 96 name: "add_property: missing prop", 97 txId: "1", 98 payload: `{"id":"1", "type": "add_property", "payload":{"class":"Foo"}}`, 99 errMustContain: "property is nil", 100 }, 101 } 102 103 for _, test := range tests { 104 t.Run(test.name, func(t *testing.T) { 105 client := http.Client{} 106 107 // open tx 108 payload := []byte(test.payload) 109 req, err := http.NewRequest(http.MethodPost, "http://localhost:7101/schema/transactions/", bytes.NewReader(payload)) 110 require.NoError(t, err) 111 112 req.Header.Add("Content-Type", "application/json") 113 114 res, err := client.Do(req) 115 require.NoError(t, err) 116 defer res.Body.Close() 117 118 // try to commit tx 119 req, err = http.NewRequest(http.MethodPut, 120 fmt.Sprintf("http://localhost:7101/schema/transactions/%s/commit", test.txId), nil) 121 require.NoError(t, err) 122 123 res, err = client.Do(req) 124 require.NoError(t, err) 125 defer res.Body.Close() 126 127 assert.Greater(t, res.StatusCode, 399) 128 resBytes, _ := io.ReadAll(res.Body) 129 assert.Contains(t, string(resBytes), test.errMustContain) 130 131 // clean up tx (so next test doesn't have concurrent tx error) 132 req, err = http.NewRequest(http.MethodDelete, 133 fmt.Sprintf("http://localhost:7101/schema/transactions/%s", test.txId), nil) 134 require.NoError(t, err) 135 136 res, err = client.Do(req) 137 require.NoError(t, err) 138 defer res.Body.Close() 139 }) 140 } 141 }