Started working on proper controllers
This commit is contained in:
		
							parent
							
								
									306640abdb
								
							
						
					
					
						commit
						6df67ce93b
					
				
							
								
								
									
										13
									
								
								internal/dynamo-browse/controllers/iface.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								internal/dynamo-browse/controllers/iface.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| package controllers | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/lmika/awstools/internal/dynamo-browse/models" | ||||
| ) | ||||
| 
 | ||||
| type TableReadService interface { | ||||
| 	ListTables(background context.Context) ([]string, error) | ||||
| 	Describe(ctx context.Context, table string) (*models.TableInfo, error) | ||||
| 	Scan(ctx context.Context, tableInfo *models.TableInfo) (*models.ResultSet, error) | ||||
| 	Filter(resultSet *models.ResultSet, filter string) *models.ResultSet | ||||
| } | ||||
|  | @ -5,13 +5,12 @@ import ( | |||
| 	tea "github.com/charmbracelet/bubbletea" | ||||
| 	"github.com/lmika/awstools/internal/common/ui/events" | ||||
| 	"github.com/lmika/awstools/internal/dynamo-browse/models" | ||||
| 	"github.com/lmika/awstools/internal/dynamo-browse/services/tables" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"sync" | ||||
| ) | ||||
| 
 | ||||
| type TableReadController struct { | ||||
| 	tableService *tables.Service | ||||
| 	tableService TableReadService | ||||
| 	tableName    string | ||||
| 
 | ||||
| 	// state
 | ||||
|  | @ -20,7 +19,7 @@ type TableReadController struct { | |||
| 	filter    string | ||||
| } | ||||
| 
 | ||||
| func NewTableReadController(tableService *tables.Service, tableName string) *TableReadController { | ||||
| func NewTableReadController(tableService TableReadService, tableName string) *TableReadController { | ||||
| 	return &TableReadController{ | ||||
| 		tableService: tableService, | ||||
| 		tableName:    tableName, | ||||
|  |  | |||
							
								
								
									
										107
									
								
								internal/dynamo-browse/controllers/tableread_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								internal/dynamo-browse/controllers/tableread_test.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | |||
| package controllers_test | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/lmika/awstools/internal/dynamo-browse/controllers" | ||||
| 	"github.com/lmika/awstools/internal/dynamo-browse/providers/dynamo" | ||||
| 	"github.com/lmika/awstools/internal/dynamo-browse/services/tables" | ||||
| 	"github.com/lmika/awstools/test/testdynamo" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func TestTableReadController_InitTable(t *testing.T) { | ||||
| 	client, cleanupFn := testdynamo.SetupTestTable(t, testData) | ||||
| 	defer cleanupFn() | ||||
| 
 | ||||
| 	provider := dynamo.NewProvider(client) | ||||
| 	service := tables.NewService(provider) | ||||
| 
 | ||||
| 	t.Run("should prompt for table if no table name provided", func(t *testing.T) { | ||||
| 		readController := controllers.NewTableReadController(service, "") | ||||
| 
 | ||||
| 		cmd := readController.Init() | ||||
| 		event := cmd() | ||||
| 
 | ||||
| 		assert.IsType(t, controllers.PromptForTableMsg{}, event) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("should scan table if table name provided", func(t *testing.T) { | ||||
| 		readController := controllers.NewTableReadController(service, "") | ||||
| 
 | ||||
| 		cmd := readController.Init() | ||||
| 		event := cmd() | ||||
| 
 | ||||
| 		assert.IsType(t, controllers.PromptForTableMsg{}, event) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestTableReadController_ListTables(t *testing.T) { | ||||
| 	client, cleanupFn := testdynamo.SetupTestTable(t, testData) | ||||
| 	defer cleanupFn() | ||||
| 
 | ||||
| 	provider := dynamo.NewProvider(client) | ||||
| 	service := tables.NewService(provider) | ||||
| 	readController := controllers.NewTableReadController(service, "") | ||||
| 
 | ||||
| 	t.Run("returns a list of tables", func(t *testing.T) { | ||||
| 		cmd := readController.ListTables() | ||||
| 		event := cmd().(controllers.PromptForTableMsg) | ||||
| 
 | ||||
| 		assert.Equal(t, []string{"alpha-table", "bravo-table"}, event.Tables) | ||||
| 
 | ||||
| 		selectedCmd := event.OnSelected("alpha-table") | ||||
| 		selectedEvent := selectedCmd() | ||||
| 
 | ||||
| 		resultSet := selectedEvent.(controllers.NewResultSet) | ||||
| 		assert.Equal(t, "alpha-table", resultSet.ResultSet.TableInfo.Name) | ||||
| 		assert.Equal(t, "pk", resultSet.ResultSet.TableInfo.Keys.PartitionKey) | ||||
| 		assert.Equal(t, "sk", resultSet.ResultSet.TableInfo.Keys.SortKey) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| var testData = []testdynamo.TestData{ | ||||
| 	{ | ||||
| 		TableName: "alpha-table", | ||||
| 		Data: []map[string]interface{}{ | ||||
| 			{ | ||||
| 				"pk":    "abc", | ||||
| 				"sk":    "111", | ||||
| 				"alpha": "This is some value", | ||||
| 			}, | ||||
| 			{ | ||||
| 				"pk":    "abc", | ||||
| 				"sk":    "222", | ||||
| 				"alpha": "This is another some value", | ||||
| 				"beta":  1231, | ||||
| 			}, | ||||
| 			{ | ||||
| 				"pk":    "bbb", | ||||
| 				"sk":    "131", | ||||
| 				"beta":  2468, | ||||
| 				"gamma": "foobar", | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, | ||||
| 	{ | ||||
| 		TableName: "bravo-table", | ||||
| 		Data: []map[string]interface{}{ | ||||
| 			{ | ||||
| 				"pk":    "foo", | ||||
| 				"sk":    "bar", | ||||
| 				"alpha": "This is some value", | ||||
| 			}, | ||||
| 			{ | ||||
| 				"pk":    "abc", | ||||
| 				"sk":    "222", | ||||
| 				"alpha": "This is another some value", | ||||
| 				"beta":  1231, | ||||
| 			}, | ||||
| 			{ | ||||
| 				"pk":    "bbb", | ||||
| 				"sk":    "131", | ||||
| 				"beta":  2468, | ||||
| 				"gamma": "foobar", | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  | @ -2,11 +2,6 @@ package controllers_test | |||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/lmika/awstools/internal/dynamo-browse/controllers" | ||||
| 	"github.com/lmika/awstools/internal/dynamo-browse/providers/dynamo" | ||||
| 	"github.com/lmika/awstools/internal/dynamo-browse/services/tables" | ||||
| 	"github.com/lmika/awstools/test/testdynamo" | ||||
| ) | ||||
| 
 | ||||
| func TestTableWriteController_ToggleReadWrite(t *testing.T) { | ||||
|  | @ -159,6 +154,7 @@ func TestTableWriteController_Delete(t *testing.T) { | |||
| 	*/ | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| type controller struct { | ||||
| 	tableName    string | ||||
| 	tableService *tables.Service | ||||
|  | @ -197,3 +193,4 @@ var testData = testdynamo.TestData{ | |||
| 		"gamma": "foobar", | ||||
| 	}, | ||||
| } | ||||
| */ | ||||
|  |  | |||
|  | @ -11,9 +11,9 @@ import ( | |||
| ) | ||||
| 
 | ||||
| func TestProvider_ScanItems(t *testing.T) { | ||||
| 	tableName := "provider-scanimages-test-table" | ||||
| 	tableName := "test-table" | ||||
| 
 | ||||
| 	client, cleanupFn := testdynamo.SetupTestTable(t, tableName, testData) | ||||
| 	client, cleanupFn := testdynamo.SetupTestTable(t, testData) | ||||
| 	defer cleanupFn() | ||||
| 	provider := dynamo.NewProvider(client) | ||||
| 
 | ||||
|  | @ -24,9 +24,9 @@ func TestProvider_ScanItems(t *testing.T) { | |||
| 		assert.NoError(t, err) | ||||
| 		assert.Len(t, items, 3) | ||||
| 
 | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[1])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[2])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0].Data[0])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0].Data[1])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0].Data[2])) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("should return error if table name does not exist", func(t *testing.T) { | ||||
|  | @ -39,10 +39,10 @@ func TestProvider_ScanItems(t *testing.T) { | |||
| } | ||||
| 
 | ||||
| func TestProvider_DeleteItem(t *testing.T) { | ||||
| 	tableName := "provider-deleteitem-test-table" | ||||
| 	tableName := "test-table" | ||||
| 
 | ||||
| 	t.Run("should delete item if exists in table", func(t *testing.T) { | ||||
| 		client, cleanupFn := testdynamo.SetupTestTable(t, tableName, testData) | ||||
| 		client, cleanupFn := testdynamo.SetupTestTable(t, testData) | ||||
| 		defer cleanupFn() | ||||
| 		provider := dynamo.NewProvider(client) | ||||
| 
 | ||||
|  | @ -57,14 +57,14 @@ func TestProvider_DeleteItem(t *testing.T) { | |||
| 		assert.NoError(t, err) | ||||
| 		assert.Len(t, items, 2) | ||||
| 
 | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[2])) | ||||
| 		assert.NotContains(t, items, testdynamo.TestRecordAsItem(t, testData[1])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0].Data[0])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0].Data[2])) | ||||
| 		assert.NotContains(t, items, testdynamo.TestRecordAsItem(t, testData[0].Data[1])) | ||||
| 
 | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("should do nothing if key does not exist", func(t *testing.T) { | ||||
| 		client, cleanupFn := testdynamo.SetupTestTable(t, tableName, testData) | ||||
| 		client, cleanupFn := testdynamo.SetupTestTable(t, testData) | ||||
| 		defer cleanupFn() | ||||
| 		provider := dynamo.NewProvider(client) | ||||
| 
 | ||||
|  | @ -79,13 +79,13 @@ func TestProvider_DeleteItem(t *testing.T) { | |||
| 		assert.NoError(t, err) | ||||
| 		assert.Len(t, items, 3) | ||||
| 
 | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[1])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[2])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0].Data[0])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0].Data[1])) | ||||
| 		assert.Contains(t, items, testdynamo.TestRecordAsItem(t, testData[0].Data[2])) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("should return error if table name does not exist", func(t *testing.T) { | ||||
| 		client, cleanupFn := testdynamo.SetupTestTable(t, tableName, testData) | ||||
| 		client, cleanupFn := testdynamo.SetupTestTable(t, testData) | ||||
| 		defer cleanupFn() | ||||
| 		provider := dynamo.NewProvider(client) | ||||
| 
 | ||||
|  | @ -97,22 +97,27 @@ func TestProvider_DeleteItem(t *testing.T) { | |||
| 	}) | ||||
| } | ||||
| 
 | ||||
| var testData = testdynamo.TestData{ | ||||
| var testData = []testdynamo.TestData{ | ||||
| 	{ | ||||
| 		"pk":    "abc", | ||||
| 		"sk":    "111", | ||||
| 		"alpha": "This is some value", | ||||
| 	}, | ||||
| 	{ | ||||
| 		"pk":    "abc", | ||||
| 		"sk":    "222", | ||||
| 		"alpha": "This is another some value", | ||||
| 		"beta":  1231, | ||||
| 	}, | ||||
| 	{ | ||||
| 		"pk":    "bbb", | ||||
| 		"sk":    "131", | ||||
| 		"beta":  2468, | ||||
| 		"gamma": "foobar", | ||||
| 		TableName: "test-table", | ||||
| 		Data: []map[string]interface{}{ | ||||
| 			{ | ||||
| 				"pk":    "abc", | ||||
| 				"sk":    "111", | ||||
| 				"alpha": "This is some value", | ||||
| 			}, | ||||
| 			{ | ||||
| 				"pk":    "abc", | ||||
| 				"sk":    "222", | ||||
| 				"alpha": "This is another some value", | ||||
| 				"beta":  1231, | ||||
| 			}, | ||||
| 			{ | ||||
| 				"pk":    "bbb", | ||||
| 				"sk":    "131", | ||||
| 				"beta":  2468, | ||||
| 				"gamma": "foobar", | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  |  | |||
|  | @ -11,9 +11,9 @@ import ( | |||
| ) | ||||
| 
 | ||||
| func TestService_Describe(t *testing.T) { | ||||
| 	tableName := "service-describe-table" | ||||
| 	tableName := "service-test-data" | ||||
| 
 | ||||
| 	client, cleanupFn := testdynamo.SetupTestTable(t, tableName, testData) | ||||
| 	client, cleanupFn := testdynamo.SetupTestTable(t, testData) | ||||
| 	defer cleanupFn() | ||||
| 	provider := dynamo.NewProvider(client) | ||||
| 
 | ||||
|  | @ -33,9 +33,9 @@ func TestService_Describe(t *testing.T) { | |||
| } | ||||
| 
 | ||||
| func TestService_Scan(t *testing.T) { | ||||
| 	tableName := "service-scan-test-table" | ||||
| 	tableName := "service-test-data" | ||||
| 
 | ||||
| 	client, cleanupFn := testdynamo.SetupTestTable(t, tableName, testData) | ||||
| 	client, cleanupFn := testdynamo.SetupTestTable(t, testData) | ||||
| 	defer cleanupFn() | ||||
| 	provider := dynamo.NewProvider(client) | ||||
| 
 | ||||
|  | @ -58,22 +58,27 @@ func TestService_Scan(t *testing.T) { | |||
| 	}) | ||||
| } | ||||
| 
 | ||||
| var testData = testdynamo.TestData{ | ||||
| var testData = []testdynamo.TestData{ | ||||
| 	{ | ||||
| 		"pk":    "abc", | ||||
| 		"sk":    "222", | ||||
| 		"alpha": "This is another some value", | ||||
| 		"beta":  1231, | ||||
| 	}, | ||||
| 	{ | ||||
| 		"pk":    "abc", | ||||
| 		"sk":    "111", | ||||
| 		"alpha": "This is some value", | ||||
| 	}, | ||||
| 	{ | ||||
| 		"pk":    "bbb", | ||||
| 		"sk":    "131", | ||||
| 		"beta":  2468, | ||||
| 		"gamma": "foobar", | ||||
| 		TableName: "service-test-data", | ||||
| 		Data: []map[string]interface{}{ | ||||
| 			{ | ||||
| 				"pk":    "abc", | ||||
| 				"sk":    "222", | ||||
| 				"alpha": "This is another some value", | ||||
| 				"beta":  1231, | ||||
| 			}, | ||||
| 			{ | ||||
| 				"pk":    "abc", | ||||
| 				"sk":    "111", | ||||
| 				"alpha": "This is some value", | ||||
| 			}, | ||||
| 			{ | ||||
| 				"pk":    "bbb", | ||||
| 				"sk":    "131", | ||||
| 				"beta":  2468, | ||||
| 				"gamma": "foobar", | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| type Model struct { | ||||
| 	submodel tea.Model | ||||
| 	submodel    tea.Model | ||||
| 	lineDetails *linedetails.Model | ||||
| 
 | ||||
| 	visible bool | ||||
|  | @ -16,7 +16,7 @@ type Model struct { | |||
| 
 | ||||
| func NewModel(submodel tea.Model) *Model { | ||||
| 	return &Model{ | ||||
| 		submodel: submodel, | ||||
| 		submodel:    submodel, | ||||
| 		lineDetails: linedetails.New(), | ||||
| 	} | ||||
| } | ||||
|  | @ -49,6 +49,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { | |||
| func (m *Model) ViewItem(item *models.LogLine) { | ||||
| 	m.visible = true | ||||
| 	m.lineDetails.SetSelectedItem(item) | ||||
| 	m.lineDetails.SetFocused(true) | ||||
| } | ||||
| 
 | ||||
| func (m *Model) View() string { | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ type itemTableRow struct { | |||
| 
 | ||||
| func (mtr itemTableRow) Render(w io.Writer, model table.Model, index int) { | ||||
| 	firstLine := strings.SplitN(mtr.item.Value, "\n", 2)[0] | ||||
| 	line := fmt.Sprintf("%s\t%s\t%s", mtr.item.Name, "String", firstLine) | ||||
| 	line := fmt.Sprintf("%s\t%s\t%s", mtr.item.Name, mtr.item.Type, firstLine) | ||||
| 
 | ||||
| 	if index == model.Cursor() { | ||||
| 		fmt.Fprintln(w, model.Styles.SelectedRow.Render(line)) | ||||
|  |  | |||
|  | @ -13,9 +13,12 @@ import ( | |||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
| 
 | ||||
| type TestData []map[string]interface{} | ||||
| type TestData struct { | ||||
| 	TableName string | ||||
| 	Data      []map[string]interface{} | ||||
| } | ||||
| 
 | ||||
| func SetupTestTable(t *testing.T, tableName string, testData TestData) (*dynamodb.Client, func()) { | ||||
| func SetupTestTable(t *testing.T, testData []TestData) (*dynamodb.Client, func()) { | ||||
| 	t.Helper() | ||||
| 	ctx := context.Background() | ||||
| 
 | ||||
|  | @ -27,37 +30,41 @@ func SetupTestTable(t *testing.T, tableName string, testData TestData) (*dynamod | |||
| 	dynamoClient := dynamodb.NewFromConfig(cfg, | ||||
| 		dynamodb.WithEndpointResolver(dynamodb.EndpointResolverFromURL("http://localhost:8000"))) | ||||
| 
 | ||||
| 	_, err = dynamoClient.CreateTable(ctx, &dynamodb.CreateTableInput{ | ||||
| 		TableName: aws.String(tableName), | ||||
| 		KeySchema: []types.KeySchemaElement{ | ||||
| 			{AttributeName: aws.String("pk"), KeyType: types.KeyTypeHash}, | ||||
| 			{AttributeName: aws.String("sk"), KeyType: types.KeyTypeRange}, | ||||
| 		}, | ||||
| 		AttributeDefinitions: []types.AttributeDefinition{ | ||||
| 			{AttributeName: aws.String("pk"), AttributeType: types.ScalarAttributeTypeS}, | ||||
| 			{AttributeName: aws.String("sk"), AttributeType: types.ScalarAttributeTypeS}, | ||||
| 		}, | ||||
| 		ProvisionedThroughput: &types.ProvisionedThroughput{ | ||||
| 			ReadCapacityUnits:  aws.Int64(100), | ||||
| 			WriteCapacityUnits: aws.Int64(100), | ||||
| 		}, | ||||
| 	}) | ||||
| 	assert.NoError(t, err) | ||||
| 
 | ||||
| 	for _, item := range testData { | ||||
| 		m, err := attributevalue.MarshalMap(item) | ||||
| 		assert.NoError(t, err) | ||||
| 
 | ||||
| 		_, err = dynamoClient.PutItem(ctx, &dynamodb.PutItemInput{ | ||||
| 			TableName: aws.String(tableName), | ||||
| 			Item:      m, | ||||
| 	for _, table := range testData { | ||||
| 		_, err = dynamoClient.CreateTable(ctx, &dynamodb.CreateTableInput{ | ||||
| 			TableName: aws.String(table.TableName), | ||||
| 			KeySchema: []types.KeySchemaElement{ | ||||
| 				{AttributeName: aws.String("pk"), KeyType: types.KeyTypeHash}, | ||||
| 				{AttributeName: aws.String("sk"), KeyType: types.KeyTypeRange}, | ||||
| 			}, | ||||
| 			AttributeDefinitions: []types.AttributeDefinition{ | ||||
| 				{AttributeName: aws.String("pk"), AttributeType: types.ScalarAttributeTypeS}, | ||||
| 				{AttributeName: aws.String("sk"), AttributeType: types.ScalarAttributeTypeS}, | ||||
| 			}, | ||||
| 			ProvisionedThroughput: &types.ProvisionedThroughput{ | ||||
| 				ReadCapacityUnits:  aws.Int64(100), | ||||
| 				WriteCapacityUnits: aws.Int64(100), | ||||
| 			}, | ||||
| 		}) | ||||
| 		assert.NoError(t, err) | ||||
| 
 | ||||
| 		for _, item := range table.Data { | ||||
| 			m, err := attributevalue.MarshalMap(item) | ||||
| 			assert.NoError(t, err) | ||||
| 
 | ||||
| 			_, err = dynamoClient.PutItem(ctx, &dynamodb.PutItemInput{ | ||||
| 				TableName: aws.String(table.TableName), | ||||
| 				Item:      m, | ||||
| 			}) | ||||
| 			assert.NoError(t, err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return dynamoClient, func() { | ||||
| 		dynamoClient.DeleteTable(ctx, &dynamodb.DeleteTableInput{ | ||||
| 			TableName: aws.String(tableName), | ||||
| 		}) | ||||
| 		for _, table := range testData { | ||||
| 			dynamoClient.DeleteTable(ctx, &dynamodb.DeleteTableInput{ | ||||
| 				TableName: aws.String(table.TableName), | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue