github.com/fafucoder/cilium@v1.6.11/proxylib/proxylib_memcached_test.go (about)

     1  // Copyright 2018 Authors of Cilium
     2  //
     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  // +build !privileged_tests
    16  
    17  package main
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	_ "github.com/cilium/cilium/proxylib/memcached"
    24  	binarymemcache "github.com/cilium/cilium/proxylib/memcached/binary"
    25  	textmemcache "github.com/cilium/cilium/proxylib/memcached/text"
    26  	"github.com/cilium/cilium/proxylib/proxylib"
    27  	"github.com/cilium/cilium/proxylib/test"
    28  
    29  	_ "gopkg.in/check.v1"
    30  )
    31  
    32  var setHelloText = []byte("set key 0 0 5\r\nhello\r\n")
    33  var setHelloTextNoreply = []byte("set key 0 0 5 noreply\r\nhello\r\n")
    34  
    35  var getKeysText = []byte("get key1 key2 key3\r\n")
    36  var gatKeysText = []byte("gat 5 key1 key2 key3\r\n")
    37  var getResponse = []byte(
    38  	"VALUE key3 0 4\r\n" +
    39  		"xDDD\r\n" +
    40  		"VALUE key4 0 3\r\n" +
    41  		"xDD\r\n" +
    42  		"END\r\n")
    43  
    44  var deleteText = []byte("delete key\r\n")
    45  var incrText = []byte("incr key 5\r\n")
    46  var touchText = []byte("touch key 55\r\n")
    47  var slabsText = []byte("slabs automove 1\r\n")
    48  var okText = []byte("OK\r\n")
    49  var lruCrawlerText = []byte("lru_crawler metadump all\r\n")
    50  var statsText = []byte("stats\r\n")
    51  var flushAllText = []byte("flush_all 15\r\n")
    52  var watchText = []byte("watch mutations\r\n")
    53  
    54  var watchReply = []byte(
    55  	"OK\r\n" +
    56  		"ts=1538135970.404892 gid=5 type=item_store key=key3 status=stored cmd=set ttl=500 clsid=1\r\n" +
    57  		"ts=1538135970.404898 gid=6 type=item_store key=key4 status=stored cmd=set ttl=500 clsid=1\r\n" +
    58  		"ts=1538135974.340708 gid=7 type=item_store key=key3 status=stored cmd=set ttl=500 clsid=1\r\n" +
    59  		"ts=1538135974.340714 gid=8 type=item_store key=key4 status=stored cmd=set ttl=500 clsid=1\r\n" +
    60  		"ts=1538135976.436863 gid=9 type=item_store key=key3 status=stored cmd=set ttl=500 clsid=1\r\n")
    61  
    62  var lruCrawlerResponse = []byte(
    63  	"key=key3 exp=1538047402 la=1538046902 cas=1 fetch=no cls=1 size=67\r\n" +
    64  		"key=key4 exp=1538047402 la=1538046902 cas=2 fetch=no cls=1 size=66\r\n" +
    65  		"END\r\n")
    66  
    67  var statsResponse = []byte(
    68  	"STAT evictions 0\r\n" +
    69  		"STAT reclaimed 2\r\n" +
    70  		"STAT crawler_reclaimed\r\n" +
    71  		"STAT crawler_items_checked 18\r\n" +
    72  		"STAT lrutail_reflocked 0\r\n" +
    73  		"STAT moves_to_cold 6\r\n" +
    74  		"STAT moves_to_warm 0\r\n" +
    75  		"STAT moves_within_lru 0\r\n" +
    76  		"STAT direct_reclaims 0\r\n" +
    77  		"STAT lru_bumps_dropped 0\r\n" +
    78  		"END\r\n")
    79  
    80  var notFound = []byte("NOT_FOUND\r\n")
    81  
    82  var stored = []byte("STORED\r\n")
    83  
    84  // binary packets
    85  var getHello = []byte{
    86  	128, 0, 0, 5,
    87  	0, 0, 0, 0,
    88  	0, 0, 0, 5,
    89  	0, 0, 0, 0,
    90  	0, 0, 0, 0,
    91  	0, 0, 0, 0,
    92  	'H', 'e', 'l', 'l',
    93  	'o',
    94  }
    95  
    96  var getHelloResp = []byte{
    97  	129, 0, 0, 0,
    98  	4, 0, 0, 0,
    99  	0, 0, 0, 9,
   100  	0, 0, 0, 0,
   101  	0, 0, 0, 0,
   102  	0, 0, 0, 0,
   103  	0, 0, 0, 0,
   104  	'W', 'o', 'r', 'l',
   105  	'd',
   106  }
   107  
   108  var setHello = []byte{
   109  	128, 1, 0, 5,
   110  	8, 0, 0, 0,
   111  	0, 0, 0, 18,
   112  	0, 0, 0, 0,
   113  	0, 0, 0, 0,
   114  	0, 0, 0, 0,
   115  	0, 0, 0, 0,
   116  	0, 0, 0, 0,
   117  	'H', 'e', 'l', 'l',
   118  	'o', 'W', 'o', 'r',
   119  	'l', 'd',
   120  }
   121  
   122  func TestMemcache(t *testing.T) {
   123  	for _, tc := range append(textTestCases, binaryTestCases...) {
   124  		t.Run(tc.name, func(t *testing.T) {
   125  
   126  			logServer := test.StartAccessLogServer("access_log.sock", 10)
   127  			defer logServer.Close()
   128  
   129  			mod := OpenModule([][2]string{{"access-log-path", logServer.Path}}, false)
   130  			if mod == 0 {
   131  				t.Errorf("OpenModule() with access log path %s failed", logServer.Path)
   132  			} else {
   133  				defer CloseModule(mod)
   134  			}
   135  
   136  			insertPolicyText(t, mod, "1", []string{fmt.Sprintf(`
   137  		name: "bm1"
   138  		policy: 2
   139  		ingress_per_port_policies: <
   140  		  port: 80
   141  		  rules: <
   142  		    remote_policies: 1
   143  		    remote_policies: 3
   144  		    remote_policies: 4
   145              l7_proto: "memcache"
   146  		    l7_rules: <
   147  		      l7_rules: <
   148  %s
   149  		      >
   150  		    >
   151  		  >
   152  		>
   153  		`, tc.policy)})
   154  
   155  			buf := CheckOnNewConnection(t, mod, "memcache", 1, true, 1, 2, "1.1.1.1:34567", "2.2.2.2:80", "bm1",
   156  				30, proxylib.OK, 1)
   157  
   158  			tc.onDataChecks(t)
   159  
   160  			CheckClose(t, 1, buf, 1)
   161  		})
   162  	}
   163  }
   164  
   165  type testCase struct {
   166  	name         string
   167  	policy       string
   168  	onDataChecks func(*testing.T)
   169  }
   170  
   171  var textTestCases = []testCase{
   172  	{
   173  		"text set pass",
   174  		`		        rule: <
   175  		          key: "keyExact"
   176  		          value: ""
   177  				>
   178  				rule: <
   179  				  key: "command"
   180  				  value: "set"
   181  		        >
   182  		`,
   183  		func(t *testing.T) {
   184  			CheckOnData(t, 1, false, false, &[][]byte{setHelloText}, []ExpFilterOp{
   185  				{proxylib.PASS, len(setHelloText)}, {proxylib.MORE, 2},
   186  			}, proxylib.OK, "")
   187  
   188  			CheckOnData(t, 1, true, false, &[][]byte{stored}, []ExpFilterOp{
   189  				{proxylib.PASS, len(stored)},
   190  			}, proxylib.OK, "")
   191  		},
   192  	},
   193  	{
   194  		"text set drop",
   195  		`		        rule: <
   196  		          key: "keyExact"
   197  		          value: "trolo"
   198  				>
   199  				rule: <
   200  				  key: "command"
   201  				  value: "set"
   202  		        >
   203  		`,
   204  		func(t *testing.T) {
   205  			CheckOnData(t, 1, false, false, &[][]byte{setHelloText}, []ExpFilterOp{
   206  				{proxylib.DROP, len(setHelloText)}, {proxylib.MORE, 2},
   207  			}, proxylib.OK, string(textmemcache.DeniedMsg))
   208  		},
   209  	},
   210  	{
   211  		"text get pass",
   212  		`		        rule: <
   213  		          key: "keyExact"
   214  		          value: ""
   215  				>
   216  				rule: <
   217  				  key: "command"
   218  				  value: "get"
   219  		        >
   220  		`,
   221  		func(t *testing.T) {
   222  			CheckOnData(t, 1, false, false, &[][]byte{getKeysText, getKeysText}, []ExpFilterOp{
   223  				{proxylib.PASS, len(getKeysText)}, {proxylib.PASS, len(getKeysText)}, {proxylib.MORE, 2},
   224  			}, proxylib.OK, "")
   225  			CheckOnData(t, 1, true, false, &[][]byte{getResponse, getResponse}, []ExpFilterOp{
   226  				{proxylib.PASS, len(getResponse)}, {proxylib.PASS, len(getResponse)},
   227  			}, proxylib.OK, "")
   228  		},
   229  	},
   230  	{
   231  		"text get more",
   232  		`		        rule: <
   233  		          key: "keyExact"
   234  		          value: ""
   235  				>
   236  				rule: <
   237  				  key: "command"
   238  				  value: "get"
   239  		        >
   240  		`,
   241  		func(t *testing.T) {
   242  			CheckOnData(t, 1, false, false, &[][]byte{getResponse[:5]}, []ExpFilterOp{
   243  				{proxylib.MORE, 2},
   244  			}, proxylib.OK, "")
   245  		},
   246  	},
   247  	{
   248  		"text get drop",
   249  		`		        rule: <
   250  		          key: "keyExact"
   251  		          value: ""
   252  				>
   253  				rule: <
   254  				  key: "command"
   255  				  value: "set"
   256  		        >
   257  		`,
   258  		func(t *testing.T) {
   259  			CheckOnData(t, 1, false, false, &[][]byte{getKeysText}, []ExpFilterOp{
   260  				{proxylib.DROP, len(getKeysText)}, {proxylib.MORE, 2},
   261  			}, proxylib.OK, string(textmemcache.DeniedMsg))
   262  		},
   263  	},
   264  	{
   265  		"text gat pass",
   266  		`		        rule: <
   267  		          key: "keyExact"
   268  		          value: ""
   269  				>
   270  				rule: <
   271  				  key: "command"
   272  				  value: "gat"
   273  		        >
   274  		`,
   275  		func(t *testing.T) {
   276  			CheckOnData(t, 1, false, false, &[][]byte{gatKeysText, gatKeysText}, []ExpFilterOp{
   277  				{proxylib.PASS, len(gatKeysText)}, {proxylib.PASS, len(gatKeysText)}, {proxylib.MORE, 2},
   278  			}, proxylib.OK, "")
   279  			CheckOnData(t, 1, true, false, &[][]byte{getResponse, getResponse}, []ExpFilterOp{
   280  				{proxylib.PASS, len(getResponse)}, {proxylib.PASS, len(getResponse)},
   281  			}, proxylib.OK, "")
   282  		},
   283  	},
   284  	{
   285  		"text gat more",
   286  		`		        rule: <
   287  		          key: "keyExact"
   288  		          value: ""
   289  				>
   290  				rule: <
   291  				  key: "command"
   292  				  value: "gat"
   293  		        >
   294  		`,
   295  		func(t *testing.T) {
   296  			CheckOnData(t, 1, false, false, &[][]byte{getResponse[:5]}, []ExpFilterOp{
   297  				{proxylib.MORE, 2},
   298  			}, proxylib.OK, "")
   299  		},
   300  	},
   301  	{
   302  		"text gat drop",
   303  		`		        rule: <
   304  		          key: "keyExact"
   305  		          value: ""
   306  				>
   307  				rule: <
   308  				  key: "command"
   309  				  value: "set"
   310  		        >
   311  		`,
   312  		func(t *testing.T) {
   313  			CheckOnData(t, 1, false, false, &[][]byte{gatKeysText}, []ExpFilterOp{
   314  				{proxylib.DROP, len(gatKeysText)}, {proxylib.MORE, 2},
   315  			}, proxylib.OK, string(textmemcache.DeniedMsg))
   316  		},
   317  	},
   318  	{
   319  		"text delete pass",
   320  		`		        rule: <
   321  		          key: "keyExact"
   322  		          value: ""
   323  				>
   324  				rule: <
   325  				  key: "command"
   326  				  value: "delete"
   327  		        >
   328  		`,
   329  		func(t *testing.T) {
   330  
   331  			CheckOnData(t, 1, false, false, &[][]byte{deleteText}, []ExpFilterOp{
   332  				{proxylib.PASS, len(deleteText)}, {proxylib.MORE, 2},
   333  			}, proxylib.OK, "")
   334  
   335  			CheckOnData(t, 1, true, false, &[][]byte{notFound}, []ExpFilterOp{
   336  				{proxylib.PASS, len(notFound)},
   337  			}, proxylib.OK, "")
   338  		},
   339  	},
   340  	{
   341  		"text delete drop",
   342  		`		        rule: <
   343  		          key: "keyExact"
   344  		          value: ""
   345  				>
   346  				rule: <
   347  				  key: "command"
   348  				  value: "set"
   349  		        >
   350  		`,
   351  		func(t *testing.T) {
   352  			CheckOnData(t, 1, false, false, &[][]byte{deleteText}, []ExpFilterOp{
   353  				{proxylib.DROP, len(deleteText)}, {proxylib.MORE, 2},
   354  			}, proxylib.OK, string(textmemcache.DeniedMsg))
   355  		},
   356  	},
   357  	{
   358  		"text incr pass",
   359  		`		        rule: <
   360  		          key: "keyExact"
   361  		          value: ""
   362  				>
   363  				rule: <
   364  				  key: "command"
   365  				  value: "incr"
   366  		        >
   367  		`,
   368  		func(t *testing.T) {
   369  
   370  			CheckOnData(t, 1, false, false, &[][]byte{incrText}, []ExpFilterOp{
   371  				{proxylib.PASS, len(incrText)}, {proxylib.MORE, 2},
   372  			}, proxylib.OK, "")
   373  
   374  			CheckOnData(t, 1, true, false, &[][]byte{notFound}, []ExpFilterOp{
   375  				{proxylib.PASS, len(notFound)},
   376  			}, proxylib.OK, "")
   377  		},
   378  	},
   379  	{
   380  		"text incr drop",
   381  		`		        rule: <
   382  		          key: "keyExact"
   383  		          value: "otherKey"
   384  				>
   385  				rule: <
   386  				  key: "command"
   387  				  value: "incr"
   388  		        >
   389  		`,
   390  		func(t *testing.T) {
   391  			CheckOnData(t, 1, false, false, &[][]byte{incrText}, []ExpFilterOp{
   392  				{proxylib.DROP, len(incrText)}, {proxylib.MORE, 2},
   393  			}, proxylib.OK, string(textmemcache.DeniedMsg))
   394  		},
   395  	},
   396  	{
   397  		"text touch pass",
   398  		`		        rule: <
   399  		          key: "keyExact"
   400  		          value: "key"
   401  				>
   402  				rule: <
   403  				  key: "command"
   404  				  value: "touch"
   405  		        >
   406  		`,
   407  		func(t *testing.T) {
   408  
   409  			CheckOnData(t, 1, false, false, &[][]byte{touchText}, []ExpFilterOp{
   410  				{proxylib.PASS, len(touchText)}, {proxylib.MORE, 2},
   411  			}, proxylib.OK, "")
   412  
   413  			CheckOnData(t, 1, true, false, &[][]byte{notFound}, []ExpFilterOp{
   414  				{proxylib.PASS, len(notFound)},
   415  			}, proxylib.OK, "")
   416  		},
   417  	},
   418  	{
   419  		"text touch drop",
   420  		`		        rule: <
   421  		          key: "keyExact"
   422  		          value: "otherKey"
   423  				>
   424  				rule: <
   425  				  key: "command"
   426  				  value: "touch"
   427  		        >
   428  		`,
   429  		func(t *testing.T) {
   430  			CheckOnData(t, 1, false, false, &[][]byte{touchText}, []ExpFilterOp{
   431  				{proxylib.DROP, len(touchText)}, {proxylib.MORE, 2},
   432  			}, proxylib.OK, string(textmemcache.DeniedMsg))
   433  		},
   434  	},
   435  	{
   436  		"text slabs pass",
   437  		`		        rule: <
   438  				  key: "command"
   439  				  value: "slabs"
   440  		        >
   441  		`,
   442  		func(t *testing.T) {
   443  
   444  			CheckOnData(t, 1, false, false, &[][]byte{slabsText}, []ExpFilterOp{
   445  				{proxylib.PASS, len(slabsText)}, {proxylib.MORE, 2},
   446  			}, proxylib.OK, "")
   447  
   448  			CheckOnData(t, 1, true, false, &[][]byte{okText}, []ExpFilterOp{
   449  				{proxylib.PASS, len(okText)},
   450  			}, proxylib.OK, "")
   451  		},
   452  	},
   453  	{
   454  		"text slabs drop",
   455  		`		        rule: <
   456  		          key: "keyExact"
   457  		          value: "otherKey"
   458  				>
   459  				rule: <
   460  				  key: "command"
   461  				  value: "touch"
   462  		        >
   463  		`,
   464  		func(t *testing.T) {
   465  			CheckOnData(t, 1, false, false, &[][]byte{slabsText}, []ExpFilterOp{
   466  				{proxylib.DROP, len(slabsText)}, {proxylib.MORE, 2},
   467  			}, proxylib.OK, string(textmemcache.DeniedMsg))
   468  		},
   469  	},
   470  	{
   471  		"text lru_crawler response req more and pass",
   472  		`		        rule: <
   473  				  key: "command"
   474  				  value: "lru_crawler"
   475  		        >
   476  		`,
   477  		func(t *testing.T) {
   478  			CheckOnData(t, 1, false, false, &[][]byte{lruCrawlerText}, []ExpFilterOp{
   479  				{proxylib.PASS, len(lruCrawlerText)}, {proxylib.MORE, 2},
   480  			}, proxylib.OK, "")
   481  
   482  			CheckOnData(t, 1, true, false, &[][]byte{lruCrawlerResponse[:5]}, []ExpFilterOp{
   483  				{proxylib.MORE, 2},
   484  			}, proxylib.OK, "")
   485  			CheckOnData(t, 1, true, false, &[][]byte{lruCrawlerResponse}, []ExpFilterOp{
   486  				{proxylib.PASS, len(lruCrawlerResponse)},
   487  			}, proxylib.OK, "")
   488  		},
   489  	},
   490  	{
   491  		"text stats response req more and pass",
   492  		`		        rule: <
   493  				  key: "command"
   494  				  value: "stats"
   495  		        >
   496  		`,
   497  		func(t *testing.T) {
   498  
   499  			CheckOnData(t, 1, false, false, &[][]byte{statsText}, []ExpFilterOp{
   500  				{proxylib.PASS, len(statsText)}, {proxylib.MORE, 2},
   501  			}, proxylib.OK, "")
   502  
   503  			CheckOnData(t, 1, true, false, &[][]byte{statsResponse[:5]}, []ExpFilterOp{
   504  				{proxylib.MORE, 2},
   505  			}, proxylib.OK, "")
   506  			CheckOnData(t, 1, true, false, &[][]byte{statsResponse}, []ExpFilterOp{
   507  				{proxylib.PASS, len(statsResponse)},
   508  			}, proxylib.OK, "")
   509  		},
   510  	},
   511  	{
   512  		"text flush_all pass",
   513  		`		        rule: <
   514  				  key: "command"
   515  				  value: "flush_all"
   516  		        >
   517  		`,
   518  		func(t *testing.T) {
   519  
   520  			CheckOnData(t, 1, false, false, &[][]byte{flushAllText}, []ExpFilterOp{
   521  				{proxylib.PASS, len(flushAllText)}, {proxylib.MORE, 2},
   522  			}, proxylib.OK, "")
   523  
   524  		},
   525  	},
   526  	{
   527  		"text flush_all denied",
   528  		`		        rule: <
   529  				  key: "command"
   530  				  value: "get"
   531  		        >
   532  		`,
   533  		func(t *testing.T) {
   534  
   535  			CheckOnData(t, 1, false, false, &[][]byte{flushAllText}, []ExpFilterOp{
   536  				{proxylib.DROP, len(flushAllText)}, {proxylib.MORE, 2},
   537  			}, proxylib.OK, string(textmemcache.DeniedMsg))
   538  
   539  		},
   540  	},
   541  	{
   542  		"text watch passed",
   543  		`		        rule: <
   544  				  key: "command"
   545  				  value: "watch"
   546  		        >
   547  		`,
   548  		func(t *testing.T) {
   549  
   550  			CheckOnData(t, 1, false, false, &[][]byte{watchText}, []ExpFilterOp{
   551  				{proxylib.PASS, len(watchText)}, {proxylib.MORE, 2},
   552  			}, proxylib.OK, "")
   553  
   554  			CheckOnData(t, 1, true, false, &[][]byte{watchReply}, []ExpFilterOp{
   555  				{proxylib.PASS, 4}, {proxylib.PASS, 91}, {proxylib.PASS, 91}, {proxylib.PASS, 91}, {proxylib.PASS, 91}, {proxylib.PASS, 91},
   556  			}, proxylib.OK, "")
   557  		},
   558  	},
   559  	{
   560  		"text partial linefeed",
   561  		`		        rule: <
   562  		          key: "keyExact"
   563  		          value: ""
   564  				>
   565  				rule: <
   566  				  key: "command"
   567  				  value: "set"
   568  		        >
   569  		`,
   570  		func(t *testing.T) {
   571  
   572  			CheckOnData(t, 1, false, false, &[][]byte{getKeysText[:len(getKeysText)-1]}, []ExpFilterOp{
   573  				{proxylib.MORE, 1},
   574  			}, proxylib.OK, "")
   575  		},
   576  	},
   577  	{
   578  		"text set pass on empty rule",
   579  		"",
   580  		func(t *testing.T) {
   581  			CheckOnData(t, 1, false, false, &[][]byte{setHelloText}, []ExpFilterOp{
   582  				{proxylib.PASS, len(setHelloText)}, {proxylib.MORE, 2},
   583  			}, proxylib.OK, "")
   584  
   585  			CheckOnData(t, 1, true, false, &[][]byte{stored}, []ExpFilterOp{
   586  				{proxylib.PASS, len(stored)},
   587  			}, proxylib.OK, "")
   588  		},
   589  	},
   590  }
   591  
   592  var binaryTestCases = []testCase{
   593  	{
   594  		"bin get pass exact key",
   595  		`		        rule: <
   596  		          key: "keyExact"
   597  		          value: "Hello"
   598  				>
   599  				rule: <
   600  				  key: "command"
   601  				  value: "get"
   602  		        >
   603  		`,
   604  		func(t *testing.T) {
   605  			CheckOnData(t, 1, false, false, &[][]byte{getHello}, []ExpFilterOp{
   606  				{proxylib.PASS, len(getHello)}, {proxylib.MORE, 24},
   607  			}, proxylib.OK, "")
   608  		},
   609  	},
   610  	{
   611  		"bin get pass prefix key",
   612  		`		        rule: <
   613  		          key: "keyPrefix"
   614  		          value: "Hell"
   615  				>
   616  				rule: <
   617  				  key: "command"
   618  				  value: "get"
   619  		        >
   620  		`,
   621  		func(t *testing.T) {
   622  			CheckOnData(t, 1, false, false, &[][]byte{getHello}, []ExpFilterOp{
   623  				{proxylib.PASS, len(getHello)}, {proxylib.MORE, 24},
   624  			}, proxylib.OK, "")
   625  		},
   626  	},
   627  	{
   628  		"bin get pass regex key",
   629  		`		        rule: <
   630  		          key: "keyRegex"
   631  		          value: "^.el.o$"
   632  				>
   633  				rule: <
   634  				  key: "command"
   635  				  value: "get"
   636  		        >
   637  		`,
   638  		func(t *testing.T) {
   639  			CheckOnData(t, 1, false, false, &[][]byte{getHello}, []ExpFilterOp{
   640  				{proxylib.PASS, len(getHello)}, {proxylib.MORE, 24},
   641  			}, proxylib.OK, "")
   642  		},
   643  	},
   644  	{
   645  		"bin get drop",
   646  		`		        rule: <
   647  		          key: "keyExact"
   648  		          value: ""
   649  				>
   650  				rule: <
   651  				  key: "command"
   652  				  value: "set"
   653  		        >
   654  		`,
   655  		func(t *testing.T) {
   656  			CheckOnData(t, 1, false, false, &[][]byte{getHello}, []ExpFilterOp{
   657  				{proxylib.DROP, len(getHello)}, {proxylib.MORE, 24},
   658  			}, proxylib.OK, string(binarymemcache.DeniedMsgBase))
   659  		},
   660  	},
   661  	{
   662  		"bin get more",
   663  		`		        rule: <
   664  		          key: "keyExact"
   665  		          value: ""
   666  				>
   667  				rule: <
   668  				  key: "command"
   669  				  value: "get"
   670  		        >
   671  		`,
   672  		func(t *testing.T) {
   673  			data := getHello[:10]
   674  			CheckOnData(t, 1, false, false, &[][]byte{data}, []ExpFilterOp{{proxylib.MORE, 14}}, proxylib.OK, "")
   675  		},
   676  	},
   677  	{
   678  		"bin get split",
   679  		`		        rule: <
   680  		          key: "keyExact"
   681  		          value: ""
   682  				>
   683  				rule: <
   684  				  key: "command"
   685  				  value: "get"
   686  		        >
   687  		`,
   688  		func(t *testing.T) {
   689  			data := getHello
   690  			CheckOnData(t, 1, false, false, &[][]byte{data[:10], data[10:]}, []ExpFilterOp{
   691  				{proxylib.PASS, len(data)}, {proxylib.MORE, 24},
   692  			}, proxylib.OK, "")
   693  		},
   694  	},
   695  	{
   696  		"bin get remaining key",
   697  		`		        rule: <
   698  		          key: "keyExact"
   699  		          value: ""
   700  				>
   701  				rule: <
   702  				  key: "command"
   703  				  value: "get"
   704  		        >
   705  		`,
   706  		func(t *testing.T) {
   707  			data := getHello[:26]
   708  			CheckOnData(t, 1, false, false, &[][]byte{data}, []ExpFilterOp{
   709  				{proxylib.MORE, 3},
   710  			}, proxylib.OK, "")
   711  		},
   712  	},
   713  	{
   714  		"bin set drop and allow",
   715  		`		        rule: <
   716  		          key: "keyExact"
   717  		          value: ""
   718  				>
   719  				rule: <
   720  				  key: "command"
   721  				  value: "set"
   722  		        >
   723  		`,
   724  		func(t *testing.T) {
   725  			CheckOnData(t, 1, false, false, &[][]byte{setHello, getHello}, []ExpFilterOp{
   726  				{proxylib.PASS, len(setHello)}, {proxylib.DROP, len(getHello)}, {proxylib.MORE, 24},
   727  			}, proxylib.OK, string(binarymemcache.DeniedMsgBase))
   728  
   729  			CheckOnData(t, 1, true, false, &[][]byte{getHelloResp}, []ExpFilterOp{
   730  				{proxylib.PASS, len(getHelloResp)}, {proxylib.INJECT, len(binarymemcache.DeniedMsgBase)},
   731  			}, proxylib.OK, string(binarymemcache.DeniedMsgBase))
   732  		},
   733  	},
   734  }