github.com/nats-io/jwt/v2@v2.5.6/v1compat/exports_test.go (about) 1 /* 2 * Copyright 2018 The NATS Authors 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package jwt 17 18 import ( 19 "sort" 20 "testing" 21 "time" 22 ) 23 24 func TestSimpleExportValidation(t *testing.T) { 25 e := &Export{Subject: "foo", Type: Stream} 26 27 vr := CreateValidationResults() 28 e.Validate(vr) 29 30 if !vr.IsEmpty() { 31 t.Errorf("simple export should validate cleanly") 32 } 33 34 e.Type = Service 35 vr = CreateValidationResults() 36 e.Validate(vr) 37 38 if !vr.IsEmpty() { 39 t.Errorf("simple export should validate cleanly") 40 } 41 } 42 43 func TestResponseTypeValidation(t *testing.T) { 44 e := &Export{Subject: "foo", Type: Stream, ResponseType: ResponseTypeSingleton} 45 46 vr := CreateValidationResults() 47 e.Validate(vr) 48 49 if vr.IsEmpty() { 50 t.Errorf("response type on stream should have an validation issue") 51 } 52 if e.IsSingleResponse() { 53 t.Errorf("response type should always fail for stream") 54 } 55 56 e.Type = Service 57 vr = CreateValidationResults() 58 e.Validate(vr) 59 if !vr.IsEmpty() { 60 t.Errorf("response type on service should validate cleanly") 61 } 62 if !e.IsSingleResponse() || e.IsChunkedResponse() || e.IsStreamResponse() { 63 t.Errorf("response type should be single") 64 } 65 66 e.ResponseType = ResponseTypeChunked 67 vr = CreateValidationResults() 68 e.Validate(vr) 69 if !vr.IsEmpty() { 70 t.Errorf("response type on service should validate cleanly") 71 } 72 if e.IsSingleResponse() || !e.IsChunkedResponse() || e.IsStreamResponse() { 73 t.Errorf("response type should be chunk") 74 } 75 76 e.ResponseType = ResponseTypeStream 77 vr = CreateValidationResults() 78 e.Validate(vr) 79 if !vr.IsEmpty() { 80 t.Errorf("response type on service should validate cleanly") 81 } 82 if e.IsSingleResponse() || e.IsChunkedResponse() || !e.IsStreamResponse() { 83 t.Errorf("response type should be stream") 84 } 85 86 e.ResponseType = "" 87 vr = CreateValidationResults() 88 e.Validate(vr) 89 if !vr.IsEmpty() { 90 t.Errorf("response type on service should validate cleanly") 91 } 92 if !e.IsSingleResponse() || e.IsChunkedResponse() || e.IsStreamResponse() { 93 t.Errorf("response type should be single") 94 } 95 96 e.ResponseType = "bad" 97 vr = CreateValidationResults() 98 e.Validate(vr) 99 if vr.IsEmpty() { 100 t.Errorf("response type should match available options") 101 } 102 if e.IsSingleResponse() || e.IsChunkedResponse() || e.IsStreamResponse() { 103 t.Errorf("response type should be bad") 104 } 105 } 106 107 func TestInvalidExportType(t *testing.T) { 108 i := &Export{Subject: "foo", Type: Unknown} 109 110 vr := CreateValidationResults() 111 i.Validate(vr) 112 113 if vr.IsEmpty() { 114 t.Errorf("export with bad type should not validate cleanly") 115 } 116 117 if !vr.IsBlocking(true) { 118 t.Errorf("invalid type is blocking") 119 } 120 } 121 122 func TestOverlappingExports(t *testing.T) { 123 i := &Export{Subject: "bar.foo", Type: Stream} 124 i2 := &Export{Subject: "bar.*", Type: Stream} 125 126 exports := &Exports{} 127 exports.Add(i, i2) 128 129 vr := CreateValidationResults() 130 exports.Validate(vr) 131 132 if len(vr.Issues) != 1 { 133 t.Errorf("export has overlapping subjects") 134 } 135 } 136 137 func TestDifferentExportTypes_OverlapOK(t *testing.T) { 138 i := &Export{Subject: "bar.foo", Type: Service} 139 i2 := &Export{Subject: "bar.*", Type: Stream} 140 141 exports := &Exports{} 142 exports.Add(i, i2) 143 144 vr := CreateValidationResults() 145 exports.Validate(vr) 146 147 if len(vr.Issues) != 0 { 148 t.Errorf("should allow overlaps on different export kind") 149 } 150 } 151 152 func TestDifferentExportTypes_SameSubjectOK(t *testing.T) { 153 i := &Export{Subject: "bar", Type: Service} 154 i2 := &Export{Subject: "bar", Type: Stream} 155 156 exports := &Exports{} 157 exports.Add(i, i2) 158 159 vr := CreateValidationResults() 160 exports.Validate(vr) 161 162 if len(vr.Issues) != 0 { 163 t.Errorf("should allow overlaps on different export kind") 164 } 165 } 166 167 func TestSameExportType_SameSubject(t *testing.T) { 168 i := &Export{Subject: "bar", Type: Service} 169 i2 := &Export{Subject: "bar", Type: Service} 170 171 exports := &Exports{} 172 exports.Add(i, i2) 173 174 vr := CreateValidationResults() 175 exports.Validate(vr) 176 177 if len(vr.Issues) != 1 { 178 t.Errorf("should not allow same subject on same export kind") 179 } 180 } 181 182 func TestExportRevocation(t *testing.T) { 183 akp := createAccountNKey(t) 184 apk := publicKey(akp, t) 185 account := NewAccountClaims(apk) 186 e := &Export{Subject: "foo", Type: Stream} 187 188 account.Exports.Add(e) 189 190 pubKey := "bar" 191 now := time.Now() 192 193 // test that clear is safe before we add any 194 e.ClearRevocation(pubKey) 195 196 if e.IsRevokedAt(pubKey, now) { 197 t.Errorf("no revocation was added so is revoked should be false") 198 } 199 200 e.RevokeAt(pubKey, now.Add(time.Second*100)) 201 202 if !e.IsRevokedAt(pubKey, now) { 203 t.Errorf("revocation should hold when timestamp is in the future") 204 } 205 206 if e.IsRevokedAt(pubKey, now.Add(time.Second*150)) { 207 t.Errorf("revocation should time out") 208 } 209 210 e.RevokeAt(pubKey, now.Add(time.Second*50)) // shouldn't change the revocation, you can't move it in 211 212 if !e.IsRevokedAt(pubKey, now.Add(time.Second*60)) { 213 t.Errorf("revocation should hold, 100 > 50") 214 } 215 216 encoded, _ := account.Encode(akp) 217 decoded, _ := DecodeAccountClaims(encoded) 218 219 if !decoded.Exports[0].IsRevokedAt(pubKey, now.Add(time.Second*60)) { 220 t.Errorf("revocation should last across encoding") 221 } 222 223 e.ClearRevocation(pubKey) 224 225 if e.IsRevokedAt(pubKey, now) { 226 t.Errorf("revocations should be cleared") 227 } 228 229 e.RevokeAt(pubKey, now.Add(time.Second*1000)) 230 231 if !e.IsRevoked(pubKey) { 232 t.Errorf("revocation be true we revoked in the future") 233 } 234 } 235 236 func TestExportTrackLatency(t *testing.T) { 237 e := &Export{Subject: "foo", Type: Service} 238 e.Latency = &ServiceLatency{Sampling: 100, Results: "results"} 239 vr := CreateValidationResults() 240 e.Validate(vr) 241 if !vr.IsEmpty() { 242 t.Errorf("Expected to validate with simple tracking") 243 } 244 245 e = &Export{Subject: "foo", Type: Stream} 246 e.Latency = &ServiceLatency{Sampling: 100, Results: "results"} 247 vr = CreateValidationResults() 248 e.Validate(vr) 249 if vr.IsEmpty() { 250 t.Errorf("adding latency tracking to a stream should have an validation issue") 251 } 252 253 e = &Export{Subject: "foo", Type: Service} 254 e.Latency = &ServiceLatency{Sampling: 0, Results: "results"} 255 vr = CreateValidationResults() 256 e.Validate(vr) 257 if vr.IsEmpty() { 258 t.Errorf("Sampling <1 should have a validation issue") 259 } 260 261 e = &Export{Subject: "foo", Type: Service} 262 e.Latency = &ServiceLatency{Sampling: 122, Results: "results"} 263 vr = CreateValidationResults() 264 e.Validate(vr) 265 if vr.IsEmpty() { 266 t.Errorf("Sampling >100 should have a validation issue") 267 } 268 269 e = &Export{Subject: "foo", Type: Service} 270 e.Latency = &ServiceLatency{Sampling: 22, Results: "results.*"} 271 vr = CreateValidationResults() 272 e.Validate(vr) 273 if vr.IsEmpty() { 274 t.Errorf("Results subject needs to be valid publish subject") 275 } 276 } 277 278 func TestExport_Sorting(t *testing.T) { 279 var exports Exports 280 exports.Add(&Export{Subject: "x", Type: Service}) 281 exports.Add(&Export{Subject: "z", Type: Service}) 282 exports.Add(&Export{Subject: "y", Type: Service}) 283 if exports[0].Subject != "x" { 284 t.Fatal("added export not in expected order") 285 } 286 sort.Sort(exports) 287 if exports[0].Subject != "x" && exports[1].Subject != "y" && exports[2].Subject != "z" { 288 t.Fatal("exports not sorted") 289 } 290 }