github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/cloud/spotfeed/parser_test.go (about)

     1  package spotfeed
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/require"
     9  )
    10  
    11  func TestParseFeedFileSuccess(t *testing.T) {
    12  	for _, test := range []struct {
    13  		name            string
    14  		feedBlob        string
    15  		expectedEntries []*Entry
    16  	}{
    17  		{
    18  			name: "empty",
    19  			feedBlob: `#Version: 1.0
    20  #Fields: Timestamp UsageType Operation InstanceID MyBidID MyMaxPrice MarketPrice Charge Version`,
    21  			expectedEntries: []*Entry{},
    22  		},
    23  		{
    24  			name: "one line",
    25  			feedBlob: `#Version: 1.0
    26  #Fields: Timestamp UsageType Operation InstanceID MyBidID MyMaxPrice MarketPrice Charge Version
    27  2020-10-29 19:35:44 UTC	USW2-SpotUsage:c4.large	RunInstances:SV002	i-00028539b6b1de1c0	sir-yzyi9qrm	0.100 USD	0.034 USD	0.001 USD	1`,
    28  			expectedEntries: []*Entry{
    29  				{
    30  					AccountId:      testAccountId,
    31  					Timestamp:      time.Date(2020, 10, 29, 19, 35, 44, 0, time.UTC),
    32  					UsageType:      "USW2-SpotUsage:c4.large",
    33  					Instance:       "c4.large",
    34  					Operation:      "RunInstances:SV002",
    35  					InstanceID:     "i-00028539b6b1de1c0",
    36  					MyBidID:        "sir-yzyi9qrm",
    37  					MyMaxPriceUSD:  0.1,
    38  					MarketPriceUSD: 0.034,
    39  					ChargeUSD:      0.001,
    40  					Version:        1,
    41  				},
    42  			},
    43  		},
    44  		{
    45  			name: "m1.small",
    46  			feedBlob: `#Version: 1.0
    47  #Fields: Timestamp UsageType Operation InstanceID MyBidID MyMaxPrice MarketPrice Charge Version
    48  2020-10-29 19:38:33 UTC	USW2-SpotUsage	RunInstances:SV002	i-0c5a748cea172ba6b	sir-7nigaazp	26.688 USD	8.006 USD	4.546 USD	1`,
    49  			expectedEntries: []*Entry{
    50  				{
    51  					AccountId:      testAccountId,
    52  					Timestamp:      time.Date(2020, 10, 29, 19, 38, 33, 0, time.UTC),
    53  					UsageType:      "USW2-SpotUsage",
    54  					Instance:       "m1.small",
    55  					Operation:      "RunInstances:SV002",
    56  					InstanceID:     "i-0c5a748cea172ba6b",
    57  					MyBidID:        "sir-7nigaazp",
    58  					MyMaxPriceUSD:  26.688,
    59  					MarketPriceUSD: 8.006,
    60  					ChargeUSD:      4.546,
    61  					Version:        1,
    62  				},
    63  			},
    64  		},
    65  		{
    66  			name: "multiple",
    67  			feedBlob: `#Version: 1.0
    68  #Fields: Timestamp UsageType Operation InstanceID MyBidID MyMaxPrice MarketPrice Charge Version
    69  2020-10-29 19:35:44 UTC	USW2-SpotUsage:c4.large	RunInstances:SV002	i-00028539b6b1de1c0	sir-yzyi9qrm	0.100 USD	0.034 USD	0.001 USD	1
    70  2020-10-29 19:35:05 UTC	USW2-SpotUsage:c4.large	RunInstances:SV002	i-0003301e05abdf3c1	sir-5d78aggq	0.100 USD	0.034 USD	0.002 USD	1
    71  2020-10-29 19:35:44 UTC	USW2-SpotUsage:c4.large	RunInstances:SV002	i-0028e565fd6e3d37b	sir-9g7ibe6n	0.100 USD	0.034 USD	0.002 USD	1`,
    72  			expectedEntries: []*Entry{
    73  				{
    74  					AccountId:      testAccountId,
    75  					Timestamp:      time.Date(2020, 10, 29, 19, 35, 44, 0, time.UTC),
    76  					UsageType:      "USW2-SpotUsage:c4.large",
    77  					Instance:       "c4.large",
    78  					Operation:      "RunInstances:SV002",
    79  					InstanceID:     "i-00028539b6b1de1c0",
    80  					MyBidID:        "sir-yzyi9qrm",
    81  					MyMaxPriceUSD:  0.1,
    82  					MarketPriceUSD: 0.034,
    83  					ChargeUSD:      0.001,
    84  					Version:        1,
    85  				},
    86  				{
    87  					AccountId:      testAccountId,
    88  					Timestamp:      time.Date(2020, 10, 29, 19, 35, 05, 0, time.UTC),
    89  					UsageType:      "USW2-SpotUsage:c4.large",
    90  					Instance:       "c4.large",
    91  					Operation:      "RunInstances:SV002",
    92  					InstanceID:     "i-0003301e05abdf3c1",
    93  					MyBidID:        "sir-5d78aggq",
    94  					MyMaxPriceUSD:  0.1,
    95  					MarketPriceUSD: 0.034,
    96  					ChargeUSD:      0.002,
    97  					Version:        1,
    98  				},
    99  				{
   100  					AccountId:      testAccountId,
   101  					Timestamp:      time.Date(2020, 10, 29, 19, 35, 44, 0, time.UTC),
   102  					UsageType:      "USW2-SpotUsage:c4.large",
   103  					Instance:       "c4.large",
   104  					Operation:      "RunInstances:SV002",
   105  					InstanceID:     "i-0028e565fd6e3d37b",
   106  					MyBidID:        "sir-9g7ibe6n",
   107  					MyMaxPriceUSD:  0.1,
   108  					MarketPriceUSD: 0.034,
   109  					ChargeUSD:      0.002,
   110  					Version:        1,
   111  				},
   112  			},
   113  		},
   114  	} {
   115  		t.Run(test.name, func(t *testing.T) {
   116  			entries, err := ParseFeedFile(strings.NewReader(test.feedBlob), testAccountId)
   117  			require.NoError(t, err, "failed to parse feed blob")
   118  			require.Equal(t, test.expectedEntries, entries)
   119  		})
   120  	}
   121  }
   122  
   123  func TestParseFeedFileNameSuccess(t *testing.T) {
   124  	for _, test := range []struct {
   125  		name         string
   126  		fileName     string
   127  		expectedMeta *fileMeta
   128  	}{
   129  		{
   130  			"no_gzip",
   131  			testAccountId + ".2021-02-23-04.004.8a6d6bb8",
   132  			&fileMeta{
   133  				nil,
   134  				testAccountId + ".2021-02-23-04.004.8a6d6bb8",
   135  				testAccountId,
   136  				time.Date(2021, 02, 23, 04, 0, 0, 0, time.UTC),
   137  				4,
   138  				false,
   139  			},
   140  		},
   141  		{
   142  			"gzip",
   143  			testAccountId + ".2021-02-23-04.004.8a6d6bb8.gz",
   144  			&fileMeta{
   145  				nil,
   146  				testAccountId + ".2021-02-23-04.004.8a6d6bb8.gz",
   147  				testAccountId,
   148  				time.Date(2021, 02, 23, 04, 0, 0, 0, time.UTC),
   149  				4,
   150  				true,
   151  			},
   152  		},
   153  	} {
   154  		t.Run(test.name, func(t *testing.T) {
   155  			meta, err := parseFeedFileName(test.fileName)
   156  			require.NoError(t, err, "failed to parse feed file name")
   157  			require.Equal(t, test.expectedMeta, meta)
   158  		})
   159  	}
   160  }
   161  
   162  func TestParseFeedFileNameError(t *testing.T) {
   163  	for _, test := range []struct {
   164  		name        string
   165  		fileName    string
   166  		expectedErr string
   167  	}{
   168  		{
   169  			"fail_regex",
   170  			testAccountId + ".2021-02-23-04.004.8bb8",
   171  			"does not match",
   172  		},
   173  		{
   174  			"invalid_extension",
   175  			testAccountId + ".2021-02-23-04.004.8a6d6bb8.zip",
   176  			"does not match",
   177  		},
   178  		{
   179  			"invalid_date",
   180  			testAccountId + ".2021-13-23-04.004.8a6d6bb8.gz",
   181  			"failed to parse timestamp",
   182  		},
   183  	} {
   184  		t.Run(test.name, func(t *testing.T) {
   185  			_, err := parseFeedFileName(test.fileName)
   186  			require.Error(t, err, "unexpected error while parsing feed file name %s but call to parseFeedFileName succeeded", test.fileName)
   187  			require.Contains(t, err.Error(), test.expectedErr)
   188  		})
   189  	}
   190  }