decisions_service_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. package apiclient
  2. import (
  3. "context"
  4. "fmt"
  5. "net/http"
  6. "net/url"
  7. "reflect"
  8. "testing"
  9. "github.com/crowdsecurity/go-cs-lib/pkg/ptr"
  10. "github.com/crowdsecurity/go-cs-lib/pkg/version"
  11. "github.com/crowdsecurity/crowdsec/pkg/models"
  12. "github.com/crowdsecurity/crowdsec/pkg/modelscapi"
  13. log "github.com/sirupsen/logrus"
  14. "github.com/stretchr/testify/assert"
  15. "github.com/stretchr/testify/require"
  16. )
  17. func TestDecisionsList(t *testing.T) {
  18. log.SetLevel(log.DebugLevel)
  19. mux, urlx, teardown := setup()
  20. defer teardown()
  21. mux.HandleFunc("/decisions", func(w http.ResponseWriter, r *http.Request) {
  22. testMethod(t, r, "GET")
  23. if r.URL.RawQuery == "ip=1.2.3.4" {
  24. assert.Equal(t, r.URL.RawQuery, "ip=1.2.3.4")
  25. assert.Equal(t, r.Header.Get("X-Api-Key"), "ixu")
  26. w.WriteHeader(http.StatusOK)
  27. w.Write([]byte(`[{"duration":"3h59m55.756182786s","id":4,"origin":"cscli","scenario":"manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'","scope":"Ip","type":"ban","value":"1.2.3.4"}]`))
  28. } else {
  29. w.WriteHeader(http.StatusOK)
  30. w.Write([]byte(`null`))
  31. //no results
  32. }
  33. })
  34. apiURL, err := url.Parse(urlx + "/")
  35. if err != nil {
  36. t.Fatalf("parsing api url: %s", apiURL)
  37. }
  38. //ok answer
  39. auth := &APIKeyTransport{
  40. APIKey: "ixu",
  41. }
  42. newcli, err := NewDefaultClient(apiURL, "v1", "toto", auth.Client())
  43. if err != nil {
  44. t.Fatalf("new api client: %s", err)
  45. }
  46. tduration := "3h59m55.756182786s"
  47. torigin := "cscli"
  48. tscenario := "manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'"
  49. tscope := "Ip"
  50. ttype := "ban"
  51. tvalue := "1.2.3.4"
  52. expected := &models.GetDecisionsResponse{
  53. &models.Decision{
  54. Duration: &tduration,
  55. ID: 4,
  56. Origin: &torigin,
  57. Scenario: &tscenario,
  58. Scope: &tscope,
  59. Type: &ttype,
  60. Value: &tvalue,
  61. },
  62. }
  63. //OK decisions
  64. decisionsFilter := DecisionsListOpts{IPEquals: new(string)}
  65. *decisionsFilter.IPEquals = "1.2.3.4"
  66. decisions, resp, err := newcli.Decisions.List(context.Background(), decisionsFilter)
  67. if resp.Response.StatusCode != http.StatusOK {
  68. t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
  69. }
  70. if err != nil {
  71. t.Fatalf("new api client: %s", err)
  72. }
  73. if !reflect.DeepEqual(*decisions, *expected) {
  74. t.Fatalf("returned %+v, want %+v", resp, expected)
  75. }
  76. //Empty return
  77. decisionsFilter = DecisionsListOpts{IPEquals: new(string)}
  78. *decisionsFilter.IPEquals = "1.2.3.5"
  79. decisions, resp, err = newcli.Decisions.List(context.Background(), decisionsFilter)
  80. require.NoError(t, err)
  81. if resp.Response.StatusCode != http.StatusOK {
  82. t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
  83. }
  84. assert.Equal(t, len(*decisions), 0)
  85. }
  86. func TestDecisionsStream(t *testing.T) {
  87. log.SetLevel(log.DebugLevel)
  88. mux, urlx, teardown := setup()
  89. defer teardown()
  90. mux.HandleFunc("/decisions/stream", func(w http.ResponseWriter, r *http.Request) {
  91. assert.Equal(t, r.Header.Get("X-Api-Key"), "ixu")
  92. testMethod(t, r, http.MethodGet)
  93. if r.Method == http.MethodGet {
  94. if r.URL.RawQuery == "startup=true" {
  95. w.WriteHeader(http.StatusOK)
  96. w.Write([]byte(`{"deleted":null,"new":[{"duration":"3h59m55.756182786s","id":4,"origin":"cscli","scenario":"manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'","scope":"Ip","type":"ban","value":"1.2.3.4"}]}`))
  97. } else {
  98. w.WriteHeader(http.StatusOK)
  99. w.Write([]byte(`{"deleted":null,"new":null}`))
  100. }
  101. }
  102. })
  103. mux.HandleFunc("/decisions", func(w http.ResponseWriter, r *http.Request) {
  104. assert.Equal(t, r.Header.Get("X-Api-Key"), "ixu")
  105. testMethod(t, r, http.MethodDelete)
  106. if r.Method == http.MethodDelete {
  107. w.WriteHeader(http.StatusOK)
  108. }
  109. })
  110. apiURL, err := url.Parse(urlx + "/")
  111. if err != nil {
  112. t.Fatalf("parsing api url: %s", apiURL)
  113. }
  114. //ok answer
  115. auth := &APIKeyTransport{
  116. APIKey: "ixu",
  117. }
  118. newcli, err := NewDefaultClient(apiURL, "v1", "toto", auth.Client())
  119. if err != nil {
  120. t.Fatalf("new api client: %s", err)
  121. }
  122. tduration := "3h59m55.756182786s"
  123. torigin := "cscli"
  124. tscenario := "manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'"
  125. tscope := "Ip"
  126. ttype := "ban"
  127. tvalue := "1.2.3.4"
  128. expected := &models.DecisionsStreamResponse{
  129. New: models.GetDecisionsResponse{
  130. &models.Decision{
  131. Duration: &tduration,
  132. ID: 4,
  133. Origin: &torigin,
  134. Scenario: &tscenario,
  135. Scope: &tscope,
  136. Type: &ttype,
  137. Value: &tvalue,
  138. },
  139. },
  140. }
  141. decisions, resp, err := newcli.Decisions.GetStream(context.Background(), DecisionsStreamOpts{Startup: true})
  142. require.NoError(t, err)
  143. if resp.Response.StatusCode != http.StatusOK {
  144. t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
  145. }
  146. if err != nil {
  147. t.Fatalf("new api client: %s", err)
  148. }
  149. if !reflect.DeepEqual(*decisions, *expected) {
  150. t.Fatalf("returned %+v, want %+v", resp, expected)
  151. }
  152. //and second call, we get empty lists
  153. decisions, resp, err = newcli.Decisions.GetStream(context.Background(), DecisionsStreamOpts{Startup: false})
  154. require.NoError(t, err)
  155. if resp.Response.StatusCode != http.StatusOK {
  156. t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
  157. }
  158. assert.Equal(t, 0, len(decisions.New))
  159. assert.Equal(t, 0, len(decisions.Deleted))
  160. //delete stream
  161. resp, err = newcli.Decisions.StopStream(context.Background())
  162. require.NoError(t, err)
  163. if resp.Response.StatusCode != http.StatusOK {
  164. t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
  165. }
  166. }
  167. func TestDecisionsStreamV3Compatibility(t *testing.T) {
  168. log.SetLevel(log.DebugLevel)
  169. mux, urlx, teardown := setupWithPrefix("v3")
  170. defer teardown()
  171. mux.HandleFunc("/decisions/stream", func(w http.ResponseWriter, r *http.Request) {
  172. assert.Equal(t, r.Header.Get("X-Api-Key"), "ixu")
  173. testMethod(t, r, http.MethodGet)
  174. if r.Method == http.MethodGet {
  175. if r.URL.RawQuery == "startup=true" {
  176. w.WriteHeader(http.StatusOK)
  177. w.Write([]byte(`{"deleted":[{"scope":"ip","decisions":["1.2.3.5"]}],"new":[{"scope":"ip", "scenario": "manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'", "decisions":[{"duration":"3h59m55.756182786s","value":"1.2.3.4"}]}]}`))
  178. } else {
  179. w.WriteHeader(http.StatusOK)
  180. w.Write([]byte(`{"deleted":null,"new":null}`))
  181. }
  182. }
  183. })
  184. apiURL, err := url.Parse(urlx + "/")
  185. if err != nil {
  186. t.Fatalf("parsing api url: %s", apiURL)
  187. }
  188. //ok answer
  189. auth := &APIKeyTransport{
  190. APIKey: "ixu",
  191. }
  192. newcli, err := NewDefaultClient(apiURL, "v3", "toto", auth.Client())
  193. if err != nil {
  194. t.Fatalf("new api client: %s", err)
  195. }
  196. tduration := "3h59m55.756182786s"
  197. torigin := "CAPI"
  198. tscenario := "manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'"
  199. tscope := "ip"
  200. ttype := "ban"
  201. tvalue := "1.2.3.4"
  202. tvalue1 := "1.2.3.5"
  203. tscenarioDeleted := "deleted"
  204. tdurationDeleted := "1h"
  205. expected := &models.DecisionsStreamResponse{
  206. New: models.GetDecisionsResponse{
  207. &models.Decision{
  208. Duration: &tduration,
  209. Origin: &torigin,
  210. Scenario: &tscenario,
  211. Scope: &tscope,
  212. Type: &ttype,
  213. Value: &tvalue,
  214. },
  215. },
  216. Deleted: models.GetDecisionsResponse{
  217. &models.Decision{
  218. Duration: &tdurationDeleted,
  219. Origin: &torigin,
  220. Scenario: &tscenarioDeleted,
  221. Scope: &tscope,
  222. Type: &ttype,
  223. Value: &tvalue1,
  224. },
  225. },
  226. }
  227. // GetStream is supposed to consume v3 payload and return v2 response
  228. decisions, resp, err := newcli.Decisions.GetStream(context.Background(), DecisionsStreamOpts{Startup: true})
  229. require.NoError(t, err)
  230. if resp.Response.StatusCode != http.StatusOK {
  231. t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
  232. }
  233. if err != nil {
  234. t.Fatalf("new api client: %s", err)
  235. }
  236. if !reflect.DeepEqual(*decisions, *expected) {
  237. t.Fatalf("returned %+v, want %+v", resp, expected)
  238. }
  239. }
  240. func TestDecisionsStreamV3(t *testing.T) {
  241. log.SetLevel(log.DebugLevel)
  242. mux, urlx, teardown := setupWithPrefix("v3")
  243. defer teardown()
  244. mux.HandleFunc("/decisions/stream", func(w http.ResponseWriter, r *http.Request) {
  245. assert.Equal(t, r.Header.Get("X-Api-Key"), "ixu")
  246. testMethod(t, r, http.MethodGet)
  247. if r.Method == http.MethodGet {
  248. w.WriteHeader(http.StatusOK)
  249. w.Write([]byte(`{"deleted":[{"scope":"ip","decisions":["1.2.3.5"]}],
  250. "new":[{"scope":"ip", "scenario": "manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'", "decisions":[{"duration":"3h59m55.756182786s","value":"1.2.3.4"}]}],
  251. "links": {"blocklists":[{"name":"blocklist1","url":"/v3/blocklist","scope":"ip","remediation":"ban","duration":"24h"}]}}`))
  252. }
  253. })
  254. apiURL, err := url.Parse(urlx + "/")
  255. if err != nil {
  256. t.Fatalf("parsing api url: %s", apiURL)
  257. }
  258. //ok answer
  259. auth := &APIKeyTransport{
  260. APIKey: "ixu",
  261. }
  262. newcli, err := NewDefaultClient(apiURL, "v3", "toto", auth.Client())
  263. if err != nil {
  264. t.Fatalf("new api client: %s", err)
  265. }
  266. tduration := "3h59m55.756182786s"
  267. tscenario := "manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'"
  268. tscope := "ip"
  269. tvalue := "1.2.3.4"
  270. tvalue1 := "1.2.3.5"
  271. tdurationBlocklist := "24h"
  272. tnameBlocklist := "blocklist1"
  273. tremediationBlocklist := "ban"
  274. tscopeBlocklist := "ip"
  275. turlBlocklist := "/v3/blocklist"
  276. expected := &modelscapi.GetDecisionsStreamResponse{
  277. New: modelscapi.GetDecisionsStreamResponseNew{
  278. &modelscapi.GetDecisionsStreamResponseNewItem{
  279. Decisions: []*modelscapi.GetDecisionsStreamResponseNewItemDecisionsItems0{
  280. {
  281. Duration: &tduration,
  282. Value: &tvalue,
  283. },
  284. },
  285. Scenario: &tscenario,
  286. Scope: &tscope,
  287. },
  288. },
  289. Deleted: modelscapi.GetDecisionsStreamResponseDeleted{
  290. &modelscapi.GetDecisionsStreamResponseDeletedItem{
  291. Scope: &tscope,
  292. Decisions: []string{
  293. tvalue1,
  294. },
  295. },
  296. },
  297. Links: &modelscapi.GetDecisionsStreamResponseLinks{
  298. Blocklists: []*modelscapi.BlocklistLink{
  299. {
  300. Duration: &tdurationBlocklist,
  301. Name: &tnameBlocklist,
  302. Remediation: &tremediationBlocklist,
  303. Scope: &tscopeBlocklist,
  304. URL: &turlBlocklist,
  305. },
  306. },
  307. },
  308. }
  309. // GetStream is supposed to consume v3 payload and return v2 response
  310. decisions, resp, err := newcli.Decisions.GetStreamV3(context.Background(), DecisionsStreamOpts{Startup: true})
  311. require.NoError(t, err)
  312. if resp.Response.StatusCode != http.StatusOK {
  313. t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
  314. }
  315. if err != nil {
  316. t.Fatalf("new api client: %s", err)
  317. }
  318. if !reflect.DeepEqual(*decisions, *expected) {
  319. t.Fatalf("returned %+v, want %+v", resp, expected)
  320. }
  321. }
  322. func TestDecisionsFromBlocklist(t *testing.T) {
  323. log.SetLevel(log.DebugLevel)
  324. mux, urlx, teardown := setupWithPrefix("v3")
  325. defer teardown()
  326. mux.HandleFunc("/blocklist", func(w http.ResponseWriter, r *http.Request) {
  327. testMethod(t, r, http.MethodGet)
  328. if r.Header.Get("If-Modified-Since") == "Sun, 01 Jan 2023 01:01:01 GMT" {
  329. w.WriteHeader(http.StatusNotModified)
  330. return
  331. }
  332. if r.Method == http.MethodGet {
  333. w.WriteHeader(http.StatusOK)
  334. w.Write([]byte("1.2.3.4\r\n1.2.3.5"))
  335. }
  336. })
  337. apiURL, err := url.Parse(urlx + "/")
  338. if err != nil {
  339. t.Fatalf("parsing api url: %s", apiURL)
  340. }
  341. //ok answer
  342. auth := &APIKeyTransport{
  343. APIKey: "ixu",
  344. }
  345. newcli, err := NewDefaultClient(apiURL, "v3", "toto", auth.Client())
  346. if err != nil {
  347. t.Fatalf("new api client: %s", err)
  348. }
  349. tvalue1 := "1.2.3.4"
  350. tvalue2 := "1.2.3.5"
  351. tdurationBlocklist := "24h"
  352. tnameBlocklist := "blocklist1"
  353. tremediationBlocklist := "ban"
  354. tscopeBlocklist := "ip"
  355. turlBlocklist := urlx + "/v3/blocklist"
  356. torigin := "lists"
  357. expected := []*models.Decision{
  358. {
  359. Duration: &tdurationBlocklist,
  360. Value: &tvalue1,
  361. Scenario: &tnameBlocklist,
  362. Scope: &tscopeBlocklist,
  363. Type: &tremediationBlocklist,
  364. Origin: &torigin,
  365. },
  366. {
  367. Duration: &tdurationBlocklist,
  368. Value: &tvalue2,
  369. Scenario: &tnameBlocklist,
  370. Scope: &tscopeBlocklist,
  371. Type: &tremediationBlocklist,
  372. Origin: &torigin,
  373. },
  374. }
  375. decisions, isModified, err := newcli.Decisions.GetDecisionsFromBlocklist(context.Background(), &modelscapi.BlocklistLink{
  376. URL: &turlBlocklist,
  377. Scope: &tscopeBlocklist,
  378. Remediation: &tremediationBlocklist,
  379. Name: &tnameBlocklist,
  380. Duration: &tdurationBlocklist,
  381. }, nil)
  382. require.NoError(t, err)
  383. assert.True(t, isModified)
  384. log.Infof("decision1: %+v", decisions[0])
  385. log.Infof("expected1: %+v", expected[0])
  386. log.Infof("decisions: %s, %s, %s, %s, %s, %s", *decisions[0].Value, *decisions[0].Duration, *decisions[0].Scenario, *decisions[0].Scope, *decisions[0].Type, *decisions[0].Origin)
  387. log.Infof("expected : %s, %s, %s, %s, %s", *expected[0].Value, *expected[0].Duration, *expected[0].Scenario, *expected[0].Scope, *expected[0].Type)
  388. log.Infof("decisions: %s, %s, %s, %s, %s", *decisions[1].Value, *decisions[1].Duration, *decisions[1].Scenario, *decisions[1].Scope, *decisions[1].Type)
  389. if err != nil {
  390. t.Fatalf("new api client: %s", err)
  391. }
  392. if !reflect.DeepEqual(decisions, expected) {
  393. t.Fatalf("returned %+v, want %+v", decisions, expected)
  394. }
  395. // test cache control
  396. _, isModified, err = newcli.Decisions.GetDecisionsFromBlocklist(context.Background(), &modelscapi.BlocklistLink{
  397. URL: &turlBlocklist,
  398. Scope: &tscopeBlocklist,
  399. Remediation: &tremediationBlocklist,
  400. Name: &tnameBlocklist,
  401. Duration: &tdurationBlocklist,
  402. }, ptr.Of("Sun, 01 Jan 2023 01:01:01 GMT"))
  403. require.NoError(t, err)
  404. assert.False(t, isModified)
  405. _, isModified, err = newcli.Decisions.GetDecisionsFromBlocklist(context.Background(), &modelscapi.BlocklistLink{
  406. URL: &turlBlocklist,
  407. Scope: &tscopeBlocklist,
  408. Remediation: &tremediationBlocklist,
  409. Name: &tnameBlocklist,
  410. Duration: &tdurationBlocklist,
  411. }, ptr.Of("Mon, 02 Jan 2023 01:01:01 GMT"))
  412. require.NoError(t, err)
  413. assert.True(t, isModified)
  414. }
  415. func TestDeleteDecisions(t *testing.T) {
  416. mux, urlx, teardown := setup()
  417. mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
  418. w.WriteHeader(http.StatusOK)
  419. w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`))
  420. })
  421. mux.HandleFunc("/decisions", func(w http.ResponseWriter, r *http.Request) {
  422. testMethod(t, r, "DELETE")
  423. assert.Equal(t, r.URL.RawQuery, "ip=1.2.3.4")
  424. w.WriteHeader(http.StatusOK)
  425. w.Write([]byte(`{"nbDeleted":"1"}`))
  426. //w.Write([]byte(`{"message":"0 deleted alerts"}`))
  427. })
  428. log.Printf("URL is %s", urlx)
  429. apiURL, err := url.Parse(urlx + "/")
  430. if err != nil {
  431. t.Fatalf("parsing api url: %s", apiURL)
  432. }
  433. client, err := NewClient(&Config{
  434. MachineID: "test_login",
  435. Password: "test_password",
  436. UserAgent: fmt.Sprintf("crowdsec/%s", version.String()),
  437. URL: apiURL,
  438. VersionPrefix: "v1",
  439. })
  440. if err != nil {
  441. t.Fatalf("new api client: %s", err)
  442. }
  443. filters := DecisionsDeleteOpts{IPEquals: new(string)}
  444. *filters.IPEquals = "1.2.3.4"
  445. deleted, _, err := client.Decisions.Delete(context.Background(), filters)
  446. if err != nil {
  447. t.Fatalf("unexpected err : %s", err)
  448. }
  449. assert.Equal(t, "1", deleted.NbDeleted)
  450. defer teardown()
  451. }
  452. func TestDecisionsStreamOpts_addQueryParamsToURL(t *testing.T) {
  453. baseURLString := "http://localhost:8080/v1/decisions/stream"
  454. type fields struct {
  455. Startup bool
  456. Scopes string
  457. ScenariosContaining string
  458. ScenariosNotContaining string
  459. }
  460. tests := []struct {
  461. name string
  462. fields fields
  463. want string
  464. wantErr bool
  465. }{
  466. {
  467. name: "no filter",
  468. want: baseURLString + "?",
  469. },
  470. {
  471. name: "startup=true",
  472. fields: fields{
  473. Startup: true,
  474. },
  475. want: baseURLString + "?startup=true",
  476. },
  477. {
  478. name: "set all params",
  479. fields: fields{
  480. Startup: true,
  481. Scopes: "ip,range",
  482. ScenariosContaining: "ssh",
  483. ScenariosNotContaining: "bf",
  484. },
  485. want: baseURLString + "?scenarios_containing=ssh&scenarios_not_containing=bf&scopes=ip%2Crange&startup=true",
  486. },
  487. }
  488. for _, tt := range tests {
  489. tt := tt
  490. t.Run(tt.name, func(t *testing.T) {
  491. o := &DecisionsStreamOpts{
  492. Startup: tt.fields.Startup,
  493. Scopes: tt.fields.Scopes,
  494. ScenariosContaining: tt.fields.ScenariosContaining,
  495. ScenariosNotContaining: tt.fields.ScenariosNotContaining,
  496. }
  497. got, err := o.addQueryParamsToURL(baseURLString)
  498. if (err != nil) != tt.wantErr {
  499. t.Errorf("DecisionsStreamOpts.addQueryParamsToURL() error = %v, wantErr %v", err, tt.wantErr)
  500. return
  501. }
  502. gotURL, err := url.Parse(got)
  503. if err != nil {
  504. t.Errorf("DecisionsStreamOpts.addQueryParamsToURL() got error while parsing URL: %s", err)
  505. }
  506. expectedURL, err := url.Parse(tt.want)
  507. if err != nil {
  508. t.Errorf("DecisionsStreamOpts.addQueryParamsToURL() got error while parsing URL: %s", err)
  509. }
  510. if *gotURL != *expectedURL {
  511. t.Errorf("DecisionsStreamOpts.addQueryParamsToURL() = %v, want %v", *gotURL, *expectedURL)
  512. }
  513. })
  514. }
  515. }
  516. // func TestDeleteOneDecision(t *testing.T) {
  517. // mux, urlx, teardown := setup()
  518. // mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
  519. // w.WriteHeader(http.StatusOK)
  520. // w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`))
  521. // })
  522. // mux.HandleFunc("/decisions/1", func(w http.ResponseWriter, r *http.Request) {
  523. // testMethod(t, r, "DELETE")
  524. // w.WriteHeader(http.StatusOK)
  525. // w.Write([]byte(`{"nbDeleted":"1"}`))
  526. // })
  527. // log.Printf("URL is %s", urlx)
  528. // apiURL, err := url.Parse(urlx + "/")
  529. // if err != nil {
  530. // t.Fatalf("parsing api url: %s", apiURL)
  531. // }
  532. // client, err := NewClient(&Config{
  533. // MachineID: "test_login",
  534. // Password: "test_password",
  535. // UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
  536. // URL: apiURL,
  537. // VersionPrefix: "v1",
  538. // })
  539. // if err != nil {
  540. // t.Fatalf("new api client: %s", err)
  541. // }
  542. // filters := DecisionsDeleteOpts{IPEquals: new(string)}
  543. // *filters.IPEquals = "1.2.3.4"
  544. // deleted, _, err := client.Decisions.Delete(context.Background(), filters)
  545. // if err != nil {
  546. // t.Fatalf("unexpected err : %s", err)
  547. // }
  548. // assert.Equal(t, "1", deleted.NbDeleted)
  549. // defer teardown()
  550. // }