github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/compiler/eval/strings_test.go (about)

     1  // Unless explicitly stated otherwise all files in this repository are licensed
     2  // under the Apache License Version 2.0.
     3  // This product includes software developed at Datadog (https://www.datadoghq.com/).
     4  // Copyright 2016-present Datadog, Inc.
     5  
     6  // Package eval holds eval related files
     7  package eval
     8  
     9  import (
    10  	"slices"
    11  	"testing"
    12  )
    13  
    14  func TestStringValues(t *testing.T) {
    15  	t.Run("scalar-fast-path", func(t *testing.T) {
    16  		var values StringValues
    17  		values.AppendScalarValue("test123")
    18  
    19  		if err := values.Compile(DefaultStringCmpOpts); err != nil {
    20  			t.Error(err)
    21  		}
    22  
    23  		if !slices.Contains(values.scalarCache, "test123") {
    24  			t.Error("expected cache key not found")
    25  		}
    26  
    27  		if len(values.stringMatchers) != 0 {
    28  			t.Error("shouldn't have a string matcher")
    29  		}
    30  	})
    31  
    32  	t.Run("scalar-matcher", func(t *testing.T) {
    33  		var values StringValues
    34  		values.AppendScalarValue("test123")
    35  
    36  		if err := values.Compile(StringCmpOpts{CaseInsensitive: true}); err != nil {
    37  			t.Error(err)
    38  		}
    39  
    40  		if slices.Contains(values.scalarCache, "test123") {
    41  			t.Error("expected cache key found")
    42  		}
    43  
    44  		if len(values.stringMatchers) == 0 {
    45  			t.Error("should have a string matcher")
    46  		}
    47  	})
    48  }
    49  
    50  func TestScalar(t *testing.T) {
    51  	t.Run("sensitive-case", func(t *testing.T) {
    52  		matcher, err := NewStringMatcher(ScalarValueType, "test123", DefaultStringCmpOpts)
    53  		if err != nil {
    54  			t.Error(err)
    55  		}
    56  
    57  		if !matcher.Matches("test123") {
    58  			t.Error("should match")
    59  		}
    60  
    61  		if matcher.Matches("TEST123") {
    62  			t.Error("shouldn't match")
    63  		}
    64  	})
    65  
    66  	t.Run("insensitive-case", func(t *testing.T) {
    67  		matcher, err := NewStringMatcher(ScalarValueType, "test123", StringCmpOpts{CaseInsensitive: true})
    68  		if err != nil {
    69  			t.Error(err)
    70  		}
    71  
    72  		if !matcher.Matches("test123") {
    73  			t.Error("should match")
    74  		}
    75  
    76  		if !matcher.Matches("TEST123") {
    77  			t.Error("should match")
    78  		}
    79  	})
    80  }
    81  
    82  func TestPattern(t *testing.T) {
    83  	t.Run("sensitive-case", func(t *testing.T) {
    84  		matcher, err := NewStringMatcher(PatternValueType, "http://test*", DefaultStringCmpOpts)
    85  		if err != nil {
    86  			t.Error(err)
    87  		}
    88  
    89  		if !matcher.Matches("http://test123") {
    90  			t.Error("should match")
    91  		}
    92  
    93  		if matcher.Matches("http://TEST123") {
    94  			t.Error("shouldn't match")
    95  		}
    96  	})
    97  
    98  	t.Run("insensitive-case", func(t *testing.T) {
    99  		matcher, err := NewStringMatcher(PatternValueType, "http://TEst*", StringCmpOpts{CaseInsensitive: true})
   100  		if err != nil {
   101  			t.Error(err)
   102  		}
   103  
   104  		if !matcher.Matches("http://test123") {
   105  			t.Error("should match")
   106  		}
   107  
   108  		if !matcher.Matches("http://TEST123") {
   109  			t.Error("should match")
   110  		}
   111  	})
   112  
   113  	t.Run("sensitive-case-scalar", func(t *testing.T) {
   114  		matcher, err := NewStringMatcher(PatternValueType, "http://test123", DefaultStringCmpOpts)
   115  		if err != nil {
   116  			t.Error(err)
   117  		}
   118  
   119  		if !matcher.Matches("http://test123") {
   120  			t.Error("should match")
   121  		}
   122  
   123  		if matcher.Matches("http://TEST123") {
   124  			t.Error("shouldn't match")
   125  		}
   126  	})
   127  
   128  	t.Run("insensitive-case-scalar", func(t *testing.T) {
   129  		matcher, err := NewStringMatcher(PatternValueType, "http://test123", StringCmpOpts{CaseInsensitive: true})
   130  		if err != nil {
   131  			t.Error(err)
   132  		}
   133  
   134  		if !matcher.Matches("http://test123") {
   135  			t.Error("should match")
   136  		}
   137  
   138  		if !matcher.Matches("http://TEST123") {
   139  			t.Error("should match")
   140  		}
   141  	})
   142  }
   143  
   144  func TestGlob(t *testing.T) {
   145  	t.Run("sensitive-case", func(t *testing.T) {
   146  		matcher, err := NewStringMatcher(GlobValueType, "/etc/test*", DefaultStringCmpOpts)
   147  		if err != nil {
   148  			t.Error(err)
   149  		}
   150  
   151  		if !matcher.Matches("/etc/test123") {
   152  			t.Error("should match")
   153  		}
   154  
   155  		if matcher.Matches("/etc/TEST123") {
   156  			t.Error("shouldn't match")
   157  		}
   158  	})
   159  
   160  	t.Run("insensitive-case", func(t *testing.T) {
   161  		matcher, err := NewStringMatcher(GlobValueType, "/etc/TEst*", StringCmpOpts{CaseInsensitive: true})
   162  		if err != nil {
   163  			t.Error(err)
   164  		}
   165  
   166  		if !matcher.Matches("/etc/test123") {
   167  			t.Error("should match")
   168  		}
   169  
   170  		if !matcher.Matches("/etc/TEST123") {
   171  			t.Error("should match")
   172  		}
   173  	})
   174  
   175  	t.Run("sensitive-case-scalar", func(t *testing.T) {
   176  		matcher, err := NewStringMatcher(GlobValueType, "/etc/test123", DefaultStringCmpOpts)
   177  		if err != nil {
   178  			t.Error(err)
   179  		}
   180  
   181  		if !matcher.Matches("/etc/test123") {
   182  			t.Error("should match")
   183  		}
   184  
   185  		if matcher.Matches("/etc/TEST123") {
   186  			t.Error("shouldn't match")
   187  		}
   188  	})
   189  
   190  	t.Run("insensitive-case-scalar", func(t *testing.T) {
   191  		matcher, err := NewStringMatcher(GlobValueType, "/etc/test123", StringCmpOpts{CaseInsensitive: true})
   192  		if err != nil {
   193  			t.Error(err)
   194  		}
   195  
   196  		if !matcher.Matches("/etc/test123") {
   197  			t.Error("should match")
   198  		}
   199  
   200  		if !matcher.Matches("/etc/TEST123") {
   201  			t.Error("should match")
   202  		}
   203  	})
   204  }
   205  
   206  func TestRegexp(t *testing.T) {
   207  	t.Run("sensitive-case", func(t *testing.T) {
   208  		matcher, err := NewStringMatcher(RegexpValueType, "test.*", DefaultStringCmpOpts)
   209  		if err != nil {
   210  			t.Error(err)
   211  		}
   212  
   213  		if !matcher.Matches("test123") {
   214  			t.Error("should match")
   215  		}
   216  
   217  		if matcher.Matches("TEST123") {
   218  			t.Error("shouldn't match")
   219  		}
   220  	})
   221  
   222  	t.Run("insensitive-case", func(t *testing.T) {
   223  		matcher, err := NewStringMatcher(RegexpValueType, "test.*", StringCmpOpts{CaseInsensitive: true})
   224  		if err != nil {
   225  			t.Error(err)
   226  		}
   227  
   228  		if !matcher.Matches("test123") {
   229  			t.Error("should match")
   230  		}
   231  
   232  		if !matcher.Matches("TEST123") {
   233  			t.Error("should match")
   234  		}
   235  	})
   236  
   237  	t.Run("multiple-string-options", func(t *testing.T) {
   238  		matcher, err := NewStringMatcher(RegexpValueType, ".*(restore|recovery|readme|instruction|how_to|ransom).*", StringCmpOpts{})
   239  		if err != nil {
   240  			t.Error(err)
   241  		}
   242  
   243  		if !matcher.Matches("123readme456") {
   244  			t.Error("should match")
   245  		}
   246  
   247  		if matcher.Matches("TEST123") {
   248  			t.Error("should not match")
   249  		}
   250  
   251  		reMatcher, ok := matcher.(*RegexpStringMatcher)
   252  		if !ok {
   253  			t.Error("should be a regex matcher")
   254  		}
   255  
   256  		if !slices.Equal([]string{"restore", "recovery", "readme", "instruction", "how_to", "ransom"}, reMatcher.stringOptionsOpt) {
   257  			t.Error("should be an optimized string option re matcher")
   258  		}
   259  	})
   260  }
   261  
   262  func BenchmarkRegexpEvaluator(b *testing.B) {
   263  	pattern := ".*(restore|recovery|readme|instruction|how_to|ransom).*"
   264  
   265  	var matcher RegexpStringMatcher
   266  	if err := matcher.Compile(pattern, false); err != nil {
   267  		b.Fatal(err)
   268  	}
   269  
   270  	b.ResetTimer()
   271  	for i := 0; i < b.N; i++ {
   272  		if !matcher.Matches("123ransom456.txt") {
   273  			b.Fatal("unexpected result")
   274  		}
   275  	}
   276  }