linux_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. // +build linux
  2. /*
  3. Copyright 2015 The Kubernetes Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package bandwidth
  15. import (
  16. "errors"
  17. "reflect"
  18. "strings"
  19. "testing"
  20. "k8s.io/apimachinery/pkg/api/resource"
  21. "k8s.io/utils/exec"
  22. fakeexec "k8s.io/utils/exec/testing"
  23. )
  24. var tcClassOutput = `class htb 1:1 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
  25. class htb 1:2 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
  26. class htb 1:3 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
  27. class htb 1:4 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
  28. `
  29. var tcClassOutput2 = `class htb 1:1 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
  30. class htb 1:2 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
  31. class htb 1:3 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
  32. class htb 1:4 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
  33. class htb 1:5 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
  34. `
  35. func TestNextClassID(t *testing.T) {
  36. tests := []struct {
  37. output string
  38. expectErr bool
  39. expected int
  40. err error
  41. }{
  42. {
  43. output: tcClassOutput,
  44. expected: 5,
  45. },
  46. {
  47. output: "\n",
  48. expected: 1,
  49. },
  50. {
  51. expected: -1,
  52. expectErr: true,
  53. err: errors.New("test error"),
  54. },
  55. }
  56. for _, test := range tests {
  57. fcmd := fakeexec.FakeCmd{
  58. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  59. func() ([]byte, error) { return []byte(test.output), test.err },
  60. },
  61. }
  62. fexec := fakeexec.FakeExec{
  63. CommandScript: []fakeexec.FakeCommandAction{
  64. func(cmd string, args ...string) exec.Cmd {
  65. return fakeexec.InitFakeCmd(&fcmd, cmd, args...)
  66. },
  67. },
  68. }
  69. shaper := &tcShaper{e: &fexec}
  70. class, err := shaper.nextClassID()
  71. if test.expectErr {
  72. if err == nil {
  73. t.Errorf("unexpected non-error")
  74. }
  75. } else {
  76. if err != nil {
  77. t.Errorf("unexpected error: %v", err)
  78. }
  79. if class != test.expected {
  80. t.Errorf("expected: %d, found %d", test.expected, class)
  81. }
  82. }
  83. }
  84. }
  85. func TestHexCIDR(t *testing.T) {
  86. tests := []struct {
  87. name string
  88. input string
  89. output string
  90. expectErr bool
  91. }{
  92. {
  93. name: "IPv4 masked",
  94. input: "1.2.3.4/16",
  95. output: "01020000/ffff0000",
  96. },
  97. {
  98. name: "IPv4 host",
  99. input: "172.17.0.2/32",
  100. output: "ac110002/ffffffff",
  101. },
  102. {
  103. name: "IPv6 masked",
  104. input: "2001:dead:beef::cafe/64",
  105. output: "2001deadbeef00000000000000000000/ffffffffffffffff0000000000000000",
  106. },
  107. {
  108. name: "IPv6 host",
  109. input: "2001::5/128",
  110. output: "20010000000000000000000000000005/ffffffffffffffffffffffffffffffff",
  111. },
  112. {
  113. name: "invalid CIDR",
  114. input: "foo",
  115. expectErr: true,
  116. },
  117. }
  118. for _, test := range tests {
  119. output, err := hexCIDR(test.input)
  120. if test.expectErr {
  121. if err == nil {
  122. t.Errorf("case %s: unexpected non-error", test.name)
  123. }
  124. } else {
  125. if err != nil {
  126. t.Errorf("case %s: unexpected error: %v", test.name, err)
  127. }
  128. if output != test.output {
  129. t.Errorf("case %s: expected: %s, saw: %s",
  130. test.name, test.output, output)
  131. }
  132. }
  133. }
  134. }
  135. func TestAsciiCIDR(t *testing.T) {
  136. tests := []struct {
  137. name string
  138. input string
  139. output string
  140. expectErr bool
  141. }{
  142. {
  143. name: "IPv4",
  144. input: "01020000/ffff0000",
  145. output: "1.2.0.0/16",
  146. },
  147. {
  148. name: "IPv4 host",
  149. input: "ac110002/ffffffff",
  150. output: "172.17.0.2/32",
  151. },
  152. {
  153. name: "IPv6",
  154. input: "2001deadbeef00000000000000000000/ffffffffffffffff0000000000000000",
  155. output: "2001:dead:beef::/64",
  156. },
  157. {
  158. name: "IPv6 host",
  159. input: "20010000000000000000000000000005/ffffffffffffffffffffffffffffffff",
  160. output: "2001::5/128",
  161. },
  162. {
  163. name: "invalid CIDR",
  164. input: "malformed",
  165. expectErr: true,
  166. },
  167. {
  168. name: "non-hex IP",
  169. input: "nonhex/32",
  170. expectErr: true,
  171. },
  172. {
  173. name: "non-hex mask",
  174. input: "01020000/badmask",
  175. expectErr: true,
  176. },
  177. }
  178. for _, test := range tests {
  179. output, err := asciiCIDR(test.input)
  180. if test.expectErr {
  181. if err == nil {
  182. t.Errorf("case %s: unexpected non-error", test.name)
  183. }
  184. } else {
  185. if err != nil {
  186. t.Errorf("case %s: unexpected error: %v", test.name, err)
  187. }
  188. if output != test.output {
  189. t.Errorf("case %s: expected: %s, saw: %s",
  190. test.name, test.output, output)
  191. }
  192. }
  193. }
  194. }
  195. var tcFilterOutput = `filter parent 1: protocol ip pref 1 u32
  196. filter parent 1: protocol ip pref 1 u32 fh 800: ht divisor 1
  197. filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
  198. match ac110002/ffffffff at 16
  199. filter parent 1: protocol ip pref 1 u32 fh 800::801 order 2049 key ht 800 bkt 0 flowid 1:2
  200. match 01020000/ffff0000 at 16
  201. `
  202. func TestFindCIDRClass(t *testing.T) {
  203. tests := []struct {
  204. cidr string
  205. output string
  206. expectErr bool
  207. expectNotFound bool
  208. expectedClass string
  209. expectedHandle string
  210. err error
  211. }{
  212. {
  213. cidr: "172.17.0.2/32",
  214. output: tcFilterOutput,
  215. expectedClass: "1:1",
  216. expectedHandle: "800::800",
  217. },
  218. {
  219. cidr: "1.2.3.4/16",
  220. output: tcFilterOutput,
  221. expectedClass: "1:2",
  222. expectedHandle: "800::801",
  223. },
  224. {
  225. cidr: "2.2.3.4/16",
  226. output: tcFilterOutput,
  227. expectNotFound: true,
  228. },
  229. {
  230. err: errors.New("test error"),
  231. expectErr: true,
  232. },
  233. }
  234. for _, test := range tests {
  235. fcmd := fakeexec.FakeCmd{
  236. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  237. func() ([]byte, error) { return []byte(test.output), test.err },
  238. },
  239. }
  240. fexec := fakeexec.FakeExec{
  241. CommandScript: []fakeexec.FakeCommandAction{
  242. func(cmd string, args ...string) exec.Cmd {
  243. return fakeexec.InitFakeCmd(&fcmd, cmd, args...)
  244. },
  245. },
  246. }
  247. shaper := &tcShaper{e: &fexec}
  248. classAndHandle, found, err := shaper.findCIDRClass(test.cidr)
  249. if test.expectErr {
  250. if err == nil {
  251. t.Errorf("unexpected non-error")
  252. }
  253. } else {
  254. if err != nil {
  255. t.Errorf("unexpected error: %v", err)
  256. }
  257. if test.expectNotFound {
  258. if found {
  259. t.Errorf("unexpectedly found an interface: %s", classAndHandle)
  260. }
  261. } else {
  262. if classAndHandle[0][0] != test.expectedClass {
  263. t.Errorf("expected class: %s, found %s", test.expectedClass, classAndHandle)
  264. }
  265. if classAndHandle[0][1] != test.expectedHandle {
  266. t.Errorf("expected handle: %s, found %s", test.expectedHandle, classAndHandle)
  267. }
  268. }
  269. }
  270. }
  271. }
  272. func TestGetCIDRs(t *testing.T) {
  273. fcmd := fakeexec.FakeCmd{
  274. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  275. func() ([]byte, error) { return []byte(tcFilterOutput), nil },
  276. },
  277. }
  278. fexec := fakeexec.FakeExec{
  279. CommandScript: []fakeexec.FakeCommandAction{
  280. func(cmd string, args ...string) exec.Cmd {
  281. return fakeexec.InitFakeCmd(&fcmd, cmd, args...)
  282. },
  283. },
  284. }
  285. shaper := &tcShaper{e: &fexec}
  286. cidrs, err := shaper.GetCIDRs()
  287. if err != nil {
  288. t.Errorf("unexpected error: %v", err)
  289. }
  290. expectedCidrs := []string{"172.17.0.2/32", "1.2.0.0/16"}
  291. if !reflect.DeepEqual(cidrs, expectedCidrs) {
  292. t.Errorf("expected: %v, saw: %v", expectedCidrs, cidrs)
  293. }
  294. }
  295. func TestLimit(t *testing.T) {
  296. tests := []struct {
  297. cidr string
  298. ingress *resource.Quantity
  299. egress *resource.Quantity
  300. expectErr bool
  301. expectedCalls int
  302. err error
  303. }{
  304. {
  305. cidr: "1.2.3.4/32",
  306. ingress: resource.NewQuantity(10, resource.DecimalSI),
  307. egress: resource.NewQuantity(20, resource.DecimalSI),
  308. expectedCalls: 6,
  309. },
  310. {
  311. cidr: "1.2.3.4/32",
  312. ingress: resource.NewQuantity(10, resource.DecimalSI),
  313. egress: nil,
  314. expectedCalls: 3,
  315. },
  316. {
  317. cidr: "1.2.3.4/32",
  318. ingress: nil,
  319. egress: resource.NewQuantity(20, resource.DecimalSI),
  320. expectedCalls: 3,
  321. },
  322. {
  323. cidr: "1.2.3.4/32",
  324. ingress: nil,
  325. egress: nil,
  326. expectedCalls: 0,
  327. },
  328. {
  329. err: errors.New("test error"),
  330. ingress: resource.NewQuantity(10, resource.DecimalSI),
  331. egress: resource.NewQuantity(20, resource.DecimalSI),
  332. expectErr: true,
  333. },
  334. }
  335. for _, test := range tests {
  336. fcmd := fakeexec.FakeCmd{
  337. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  338. func() ([]byte, error) { return []byte(tcClassOutput), test.err },
  339. func() ([]byte, error) { return []byte{}, test.err },
  340. func() ([]byte, error) { return []byte{}, test.err },
  341. func() ([]byte, error) { return []byte(tcClassOutput2), test.err },
  342. func() ([]byte, error) { return []byte{}, test.err },
  343. func() ([]byte, error) { return []byte{}, test.err },
  344. },
  345. }
  346. fexec := fakeexec.FakeExec{
  347. CommandScript: []fakeexec.FakeCommandAction{
  348. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  349. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  350. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  351. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  352. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  353. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  354. },
  355. }
  356. iface := "cbr0"
  357. shaper := &tcShaper{e: &fexec, iface: iface}
  358. if err := shaper.Limit(test.cidr, test.ingress, test.egress); err != nil && !test.expectErr {
  359. t.Errorf("unexpected error: %v", err)
  360. return
  361. } else if err == nil && test.expectErr {
  362. t.Error("unexpected non-error")
  363. return
  364. }
  365. // No more testing in the error case
  366. if test.expectErr {
  367. if fcmd.CombinedOutputCalls != 1 {
  368. t.Errorf("unexpected number of calls: %d, expected: 1", fcmd.CombinedOutputCalls)
  369. }
  370. return
  371. }
  372. if fcmd.CombinedOutputCalls != test.expectedCalls {
  373. t.Errorf("unexpected number of calls: %d, expected: %d", fcmd.CombinedOutputCalls, test.expectedCalls)
  374. }
  375. for ix := range fcmd.CombinedOutputLog {
  376. output := fcmd.CombinedOutputLog[ix]
  377. if output[0] != "tc" {
  378. t.Errorf("unexpected command: %s, expected tc", output[0])
  379. }
  380. if output[4] != iface {
  381. t.Errorf("unexpected interface: %s, expected %s (%v)", output[4], iface, output)
  382. }
  383. if ix == 1 {
  384. var expectedRate string
  385. if test.ingress != nil {
  386. expectedRate = makeKBitString(test.ingress)
  387. } else {
  388. expectedRate = makeKBitString(test.egress)
  389. }
  390. if output[11] != expectedRate {
  391. t.Errorf("unexpected ingress: %s, expected: %s", output[11], expectedRate)
  392. }
  393. if output[8] != "1:5" {
  394. t.Errorf("unexpected class: %s, expected: %s", output[8], "1:5")
  395. }
  396. }
  397. if ix == 2 {
  398. if output[15] != test.cidr {
  399. t.Errorf("unexpected cidr: %s, expected: %s", output[15], test.cidr)
  400. }
  401. if output[17] != "1:5" {
  402. t.Errorf("unexpected class: %s, expected: %s", output[17], "1:5")
  403. }
  404. }
  405. if ix == 4 {
  406. if output[11] != makeKBitString(test.egress) {
  407. t.Errorf("unexpected egress: %s, expected: %s", output[11], makeKBitString(test.egress))
  408. }
  409. if output[8] != "1:6" {
  410. t.Errorf("unexpected class: %s, expected: %s", output[8], "1:6")
  411. }
  412. }
  413. if ix == 5 {
  414. if output[15] != test.cidr {
  415. t.Errorf("unexpected cidr: %s, expected: %s", output[15], test.cidr)
  416. }
  417. if output[17] != "1:6" {
  418. t.Errorf("unexpected class: %s, expected: %s", output[17], "1:5")
  419. }
  420. }
  421. }
  422. }
  423. }
  424. func TestReset(t *testing.T) {
  425. tests := []struct {
  426. cidr string
  427. err error
  428. expectErr bool
  429. expectedHandle string
  430. expectedClass string
  431. }{
  432. {
  433. cidr: "1.2.3.4/16",
  434. expectedHandle: "800::801",
  435. expectedClass: "1:2",
  436. },
  437. {
  438. cidr: "172.17.0.2/32",
  439. expectedHandle: "800::800",
  440. expectedClass: "1:1",
  441. },
  442. {
  443. err: errors.New("test error"),
  444. expectErr: true,
  445. },
  446. }
  447. for _, test := range tests {
  448. fcmd := fakeexec.FakeCmd{
  449. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  450. func() ([]byte, error) { return []byte(tcFilterOutput), test.err },
  451. func() ([]byte, error) { return []byte{}, test.err },
  452. func() ([]byte, error) { return []byte{}, test.err },
  453. },
  454. }
  455. fexec := fakeexec.FakeExec{
  456. CommandScript: []fakeexec.FakeCommandAction{
  457. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  458. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  459. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  460. },
  461. }
  462. iface := "cbr0"
  463. shaper := &tcShaper{e: &fexec, iface: iface}
  464. if err := shaper.Reset(test.cidr); err != nil && !test.expectErr {
  465. t.Errorf("unexpected error: %v", err)
  466. return
  467. } else if test.expectErr && err == nil {
  468. t.Error("unexpected non-error")
  469. return
  470. }
  471. // No more testing in the error case
  472. if test.expectErr {
  473. if fcmd.CombinedOutputCalls != 1 {
  474. t.Errorf("unexpected number of calls: %d, expected: 1", fcmd.CombinedOutputCalls)
  475. }
  476. return
  477. }
  478. if fcmd.CombinedOutputCalls != 3 {
  479. t.Errorf("unexpected number of calls: %d, expected: 3", fcmd.CombinedOutputCalls)
  480. }
  481. for ix := range fcmd.CombinedOutputLog {
  482. output := fcmd.CombinedOutputLog[ix]
  483. if output[0] != "tc" {
  484. t.Errorf("unexpected command: %s, expected tc", output[0])
  485. }
  486. if output[4] != iface {
  487. t.Errorf("unexpected interface: %s, expected %s (%v)", output[4], iface, output)
  488. }
  489. if ix == 1 && output[12] != test.expectedHandle {
  490. t.Errorf("unexpected handle: %s, expected: %s", output[12], test.expectedHandle)
  491. }
  492. if ix == 2 && output[8] != test.expectedClass {
  493. t.Errorf("unexpected class: %s, expected: %s", output[8], test.expectedClass)
  494. }
  495. }
  496. }
  497. }
  498. var tcQdisc = "qdisc htb 1: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n"
  499. func TestReconcileInterfaceExists(t *testing.T) {
  500. fcmd := fakeexec.FakeCmd{
  501. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  502. func() ([]byte, error) { return []byte(tcQdisc), nil },
  503. },
  504. }
  505. fexec := fakeexec.FakeExec{
  506. CommandScript: []fakeexec.FakeCommandAction{
  507. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  508. },
  509. }
  510. iface := "cbr0"
  511. shaper := &tcShaper{e: &fexec, iface: iface}
  512. err := shaper.ReconcileInterface()
  513. if err != nil {
  514. t.Errorf("unexpected error: %v", err)
  515. }
  516. if fcmd.CombinedOutputCalls != 1 {
  517. t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
  518. }
  519. output := fcmd.CombinedOutputLog[0]
  520. if len(output) != 5 {
  521. t.Errorf("unexpected command: %v", output)
  522. }
  523. if output[0] != "tc" {
  524. t.Errorf("unexpected command: %s", output[0])
  525. }
  526. if output[4] != iface {
  527. t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
  528. }
  529. if output[2] != "show" {
  530. t.Errorf("unexpected action: %s", output[2])
  531. }
  532. }
  533. func testReconcileInterfaceHasNoData(t *testing.T, output string) {
  534. fcmd := fakeexec.FakeCmd{
  535. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  536. func() ([]byte, error) { return []byte(output), nil },
  537. func() ([]byte, error) { return []byte(output), nil },
  538. },
  539. }
  540. fexec := fakeexec.FakeExec{
  541. CommandScript: []fakeexec.FakeCommandAction{
  542. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  543. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  544. },
  545. }
  546. iface := "cbr0"
  547. shaper := &tcShaper{e: &fexec, iface: iface}
  548. err := shaper.ReconcileInterface()
  549. if err != nil {
  550. t.Errorf("unexpected error: %v", err)
  551. }
  552. if fcmd.CombinedOutputCalls != 2 {
  553. t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
  554. }
  555. for ix, output := range fcmd.CombinedOutputLog {
  556. if output[0] != "tc" {
  557. t.Errorf("unexpected command: %s", output[0])
  558. }
  559. if output[4] != iface {
  560. t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
  561. }
  562. if ix == 0 {
  563. if len(output) != 5 {
  564. t.Errorf("unexpected command: %v", output)
  565. }
  566. if output[2] != "show" {
  567. t.Errorf("unexpected action: %s", output[2])
  568. }
  569. }
  570. if ix == 1 {
  571. if len(output) != 11 {
  572. t.Errorf("unexpected command: %v", output)
  573. }
  574. if output[2] != "add" {
  575. t.Errorf("unexpected action: %s", output[2])
  576. }
  577. if output[7] != "1:" {
  578. t.Errorf("unexpected root class: %s", output[7])
  579. }
  580. if output[8] != "htb" {
  581. t.Errorf("unexpected qdisc algo: %s", output[8])
  582. }
  583. }
  584. }
  585. }
  586. func TestReconcileInterfaceDoesntExist(t *testing.T) {
  587. testReconcileInterfaceHasNoData(t, "\n")
  588. }
  589. var tcQdiscNoqueue = "qdisc noqueue 0: root refcnt 2 \n"
  590. func TestReconcileInterfaceExistsWithNoqueue(t *testing.T) {
  591. testReconcileInterfaceHasNoData(t, tcQdiscNoqueue)
  592. }
  593. var tcQdiscWrong = []string{
  594. "qdisc htb 2: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n",
  595. "qdisc foo 1: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n",
  596. }
  597. func TestReconcileInterfaceIsWrong(t *testing.T) {
  598. for _, test := range tcQdiscWrong {
  599. fcmd := fakeexec.FakeCmd{
  600. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  601. func() ([]byte, error) { return []byte(test), nil },
  602. func() ([]byte, error) { return []byte("\n"), nil },
  603. func() ([]byte, error) { return []byte("\n"), nil },
  604. },
  605. }
  606. fexec := fakeexec.FakeExec{
  607. CommandScript: []fakeexec.FakeCommandAction{
  608. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  609. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  610. func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
  611. },
  612. }
  613. iface := "cbr0"
  614. shaper := &tcShaper{e: &fexec, iface: iface}
  615. err := shaper.ReconcileInterface()
  616. if err != nil {
  617. t.Errorf("unexpected error: %v", err)
  618. }
  619. if fcmd.CombinedOutputCalls != 3 {
  620. t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
  621. }
  622. for ix, output := range fcmd.CombinedOutputLog {
  623. if output[0] != "tc" {
  624. t.Errorf("unexpected command: %s", output[0])
  625. }
  626. if output[4] != iface {
  627. t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
  628. }
  629. if ix == 0 {
  630. if len(output) != 5 {
  631. t.Errorf("unexpected command: %v", output)
  632. }
  633. if output[2] != "show" {
  634. t.Errorf("unexpected action: %s", output[2])
  635. }
  636. }
  637. if ix == 1 {
  638. if len(output) != 8 {
  639. t.Errorf("unexpected command: %v", output)
  640. }
  641. if output[2] != "delete" {
  642. t.Errorf("unexpected action: %s", output[2])
  643. }
  644. if output[7] != strings.Split(test, " ")[2] {
  645. t.Errorf("unexpected class: %s, expected: %s", output[7], strings.Split(test, " ")[2])
  646. }
  647. }
  648. if ix == 2 {
  649. if len(output) != 11 {
  650. t.Errorf("unexpected command: %v", output)
  651. }
  652. if output[7] != "1:" {
  653. t.Errorf("unexpected root class: %s", output[7])
  654. }
  655. if output[8] != "htb" {
  656. t.Errorf("unexpected qdisc algo: %s", output[8])
  657. }
  658. }
  659. }
  660. }
  661. }